Advanced Lane Finding Project

The goals / steps of this project are the following:

  • Compute the camera calibration matrix and distortion coefficients given a set of chessboard images.
  • Apply a distortion correction to raw images.
  • Use color transforms, gradients, etc., to create a thresholded binary image.
  • Apply a perspective transform to rectify binary image ("birds-eye view").
  • Detect lane pixels and fit to find the lane boundary.
  • Determine the curvature of the lane and vehicle position with respect to center.
  • Warp the detected lane boundaries back onto the original image.
  • Output visual display of the lane boundaries and numerical estimation of lane curvature and vehicle position.

Preperation and utilities

In [1]:
import numpy as np
import cv2
import glob
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline
#matplotlib qt
In [2]:
def show_images(images):

    num_img = len(images)
    #print(num_img)
    #plt.figure(figsize=(15,5))
    #fig, axes = plt.subplots(num_img, 1)
    #for axe, i in zip(axes.flat, range(num_img)):
    #    print(i)
    #    axe.imshow(images[i])
    #    #plt.imshow(images[i])
    for i in range(num_img):
        #print("i:",i)
        plt.figure(i)
        #plt.subplot(num_img, 1, i+1)
        
        plt.imshow(images[i])
        #plt.imshow(images[i])

#plt.show()
In [3]:
def show_two_images(img1, img2, title1="Original Image", title2="Result Image"):

    f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
    f.tight_layout()
    ax1.imshow(img1)
    ax1.set_title(title1, fontsize=50)
    ax2.imshow(img2)
    ax2.set_title(title2, fontsize=50)
    plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
In [4]:
def show_pair_images(images1, images2):
    for i in range(len(images1)):
        show_two_images(images1[i], imges2[i])

Camera calibration

First, I'll compute the camera calibration using chessboard images

In [5]:
# a function that takes an image, object points, and image points
# performs the camera calibration, image distortion correction and 
# returns the undistorted image
def cal_undistort(img, objpoints, imgpoints):
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
    img_dst = cv2.undistort(img, mtx, dist, None, mtx)
    return img_dst
In [6]:
def compute_camera_calibration(images,chessboard_size_x=9, chessboard_size_y=6):
    # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
    objp = np.zeros((chessboard_size_y*chessboard_size_x,3), np.float32)
    objp[:,:2] = np.mgrid[0:chessboard_size_x,0:chessboard_size_y].T.reshape(-1,2)

    # Arrays to store object points and image points from all the images.
    objpoints = [] # 3d points in real world space
    imgpoints = [] # 2d points in image plane.

    # Make a list of calibration images
    images_converted = []

    # Step through the list and search for chessboard corners
    for fname in images:
        #print(fname)
        img = cv2.imread(fname)
        img_converted = np.copy(img)
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

        # Find the chessboard corners
        ret, corners = cv2.findChessboardCorners(gray, (chessboard_size_x,chessboard_size_y),None)

        # If found, add object points, image points
        if ret == True:
            objpoints.append(objp)
            imgpoints.append(corners)

            # Draw and display the corners
            img_converted = cv2.drawChessboardCorners(img_converted, (chessboard_size_x,chessboard_size_y), corners, ret)
            images_converted.append(img_converted)
            
            # Undistort the original image using objpoints and imgpoints
            img_undistorted = cal_undistort(img, objpoints, imgpoints)
            show_two_images(img_converted, img_undistorted)

    return objpoints, imgpoints
In [7]:
camera_images = glob.glob('./camera_cal/calibration*.jpg')
objpoints, imgpoints = compute_camera_calibration(camera_images)

Correcting for Distortion

There are two main steps to this process: use chessboard images to obtain image points and object points, and then use the OpenCV functions cv2.calibrateCamera() and cv2.undistort() to compute the calibration and undistortion.

Try computing the calibration and undistortion in the exercise below, and if you want to play with extracting object points and image points yourself, fork the Jupyter notebook and images in this repository.

If you run into any errors as you run your code, please refer to the Examples of Useful Code section in the previous video and make sure that your code syntax matches up!

In [8]:
test_img = cv2.imread('./camera_cal/calibration2.jpg')

undistorted = cal_undistort(test_img, objpoints, imgpoints)
show_two_images(test_img, undistorted, title2="Undistorted Image")

Perspective Transform

Compute the perspective transform, M, given source and destination points:

In [9]:
##M = cv2.getPerspectiveTransform(src, dst)

Compute the inverse perspective transform:

In [10]:
##Minv = cv2.getPerspectiveTransform(dst, src)

Warp an image using the perspective transform, M:

In [11]:
##warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)

Note: When you apply a perspective transform, choosing four source points manually, as we did in this video, is often not the best option. There are many other ways to select source points. For example, many perspective transform algorithms will programmatically detect four source points in an image based on edge or corner detection and analyzing attributes like color and surrounding pixels.

Undistort and Transform Perspective

Here's a tricky quiz for you! You have now seen how to find corners, calibrate your camera, undistort an image, and apply a perspective transform. Now it's your chance to perform all these steps on an image. In the last quiz you calibrated the camera, so here I'm giving you the camera matrix, mtx, and the distortion coefficients dist to start with.

Your goal is to generate output like the image shown above. To do that, you need to write a function that takes your distorted image as input and completes the following steps:

Undistort the image using cv2.undistort() with mtx and dist Convert to grayscale Find the chessboard corners Draw corners Define 4 source points (the outer 4 corners detected in the chessboard pattern) Define 4 destination points (must be listed in the same order as src points!) Use cv2.getPerspectiveTransform() to get M, the transform matrix use cv2.warpPerspective() to apply M and warp your image to a top-down view HINT: Source points are the x and y pixel values of any four corners on your chessboard, you can extract these from the corners array output from cv2.findChessboardCorners(). Your destination points are the x and y pixel values of where you want those four corners to be mapped to in the output image. If you run into any errors as you run your code, please refer to the Examples of Useful Code section in the previous video and make sure that your code syntax matches up! For this example, please also refer back to the examples in the Calibrating Your Camera video.

In [12]:
"""
import pickle
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

# Read in the saved camera matrix and distortion coefficients
# These are the arrays you calculated using cv2.calibrateCamera()
#dist_pickle = pickle.load( open( "wide_dist_pickle.p", "rb" ) )
#mtx = dist_pickle["mtx"]
#dist = dist_pickle["dist"]

# Read in an image
img = cv2.imread('test_image2.png')
nx = 8 # the number of inside corners in x
ny = 6 # the number of inside corners in y

# MODIFY THIS FUNCTION TO GENERATE OUTPUT 
# THAT LOOKS LIKE THE IMAGE ABOVE
def corners_unwarp(img, nx, ny, mtx, dist):
    # Pass in your image into this function
    # Write code to do the following steps
    # 1) Undistort using mtx and dist
    img_dst = cv2.undistort(img, mtx, dist, None, mtx)
    # 2) Convert to grayscale
    gray = cv2.cvtColor(img_dst,cv2.COLOR_BGR2GRAY)
    # 3) Find the chessboard corners
    ret, corners = cv2.findChessboardCorners(gray, (8,6),None)
    print(ret)
    print(len(corners))
    print(corners)
    # 4) If corners found: 
    warped = np.copy(gray)
    M = None
    if ret == True:
            # a) draw corners
            img_w_corners = cv2.drawChessboardCorners(img_dst, (8,6), corners, ret)
            
            # Choose offset from image corners to plot detected corners
            # This should be chosen to present the result at the proper aspect ratio
            # My choice of 100 pixels is not exact, but close enough for our purpose here
            offset = 100 # offset for dst points
            # Grab the image shape
            img_size = (gray.shape[1], gray.shape[0])

        
            # b) define 4 source points src = np.float32([[,],[,],[,],[,]])
                 #Note: you could pick any four of the detected corners 
                 # as long as those four corners define a rectangle
                 #One especially smart way to do this would be to use four well-chosen
                 # corners that were automatically detected during the undistortion steps
                 #We recommend using the automatic detection of corners in your code
            src = np.float32([corners[0], corners[nx-1], corners[-1], corners[-nx]])
            #src = np.float32([corners[0],corners[7],corners[40],corners[47]])#([[,],[,],[,],[,]])
            # c) define 4 destination points dst = np.float32([[,],[,],[,],[,]])
            # For destination points, I'm arbitrarily choosing some points to be
            # a nice fit for displaying our warped result 
            # again, not exact, but close enough for our purposes
            dst = np.float32([[offset, offset], [img_size[0]-offset, offset], 
                                     [img_size[0]-offset, img_size[1]-offset], 
                                     [offset, img_size[1]-offset]])
            #dst = np.float32([[,],[,],[,],[,]])
            # d) use cv2.getPerspectiveTransform() to get M, the transform matrix
            M = cv2.getPerspectiveTransform(src, dst)
            # e) use cv2.warpPerspective() to warp your image to a top-down view
            warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)
            
            #warped = img_w_corners
    #delete the next two lines
    
    return warped, M

top_down, perspective_M = corners_unwarp(img, nx, ny, mtx, dist)
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(img)
ax1.set_title('Original Image', fontsize=50)
ax2.imshow(top_down)
ax2.set_title('Undistorted and Warped Image', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
"""
Out[12]:
'\nimport pickle\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\n# Read in the saved camera matrix and distortion coefficients\n# These are the arrays you calculated using cv2.calibrateCamera()\n#dist_pickle = pickle.load( open( "wide_dist_pickle.p", "rb" ) )\n#mtx = dist_pickle["mtx"]\n#dist = dist_pickle["dist"]\n\n# Read in an image\nimg = cv2.imread(\'test_image2.png\')\nnx = 8 # the number of inside corners in x\nny = 6 # the number of inside corners in y\n\n# MODIFY THIS FUNCTION TO GENERATE OUTPUT \n# THAT LOOKS LIKE THE IMAGE ABOVE\ndef corners_unwarp(img, nx, ny, mtx, dist):\n    # Pass in your image into this function\n    # Write code to do the following steps\n    # 1) Undistort using mtx and dist\n    img_dst = cv2.undistort(img, mtx, dist, None, mtx)\n    # 2) Convert to grayscale\n    gray = cv2.cvtColor(img_dst,cv2.COLOR_BGR2GRAY)\n    # 3) Find the chessboard corners\n    ret, corners = cv2.findChessboardCorners(gray, (8,6),None)\n    print(ret)\n    print(len(corners))\n    print(corners)\n    # 4) If corners found: \n    warped = np.copy(gray)\n    M = None\n    if ret == True:\n            # a) draw corners\n            img_w_corners = cv2.drawChessboardCorners(img_dst, (8,6), corners, ret)\n            \n            # Choose offset from image corners to plot detected corners\n            # This should be chosen to present the result at the proper aspect ratio\n            # My choice of 100 pixels is not exact, but close enough for our purpose here\n            offset = 100 # offset for dst points\n            # Grab the image shape\n            img_size = (gray.shape[1], gray.shape[0])\n\n        \n            # b) define 4 source points src = np.float32([[,],[,],[,],[,]])\n                 #Note: you could pick any four of the detected corners \n                 # as long as those four corners define a rectangle\n                 #One especially smart way to do this would be to use four well-chosen\n                 # corners that were automatically detected during the undistortion steps\n                 #We recommend using the automatic detection of corners in your code\n            src = np.float32([corners[0], corners[nx-1], corners[-1], corners[-nx]])\n            #src = np.float32([corners[0],corners[7],corners[40],corners[47]])#([[,],[,],[,],[,]])\n            # c) define 4 destination points dst = np.float32([[,],[,],[,],[,]])\n            # For destination points, I\'m arbitrarily choosing some points to be\n            # a nice fit for displaying our warped result \n            # again, not exact, but close enough for our purposes\n            dst = np.float32([[offset, offset], [img_size[0]-offset, offset], \n                                     [img_size[0]-offset, img_size[1]-offset], \n                                     [offset, img_size[1]-offset]])\n            #dst = np.float32([[,],[,],[,],[,]])\n            # d) use cv2.getPerspectiveTransform() to get M, the transform matrix\n            M = cv2.getPerspectiveTransform(src, dst)\n            # e) use cv2.warpPerspective() to warp your image to a top-down view\n            warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)\n            \n            #warped = img_w_corners\n    #delete the next two lines\n    \n    return warped, M\n\ntop_down, perspective_M = corners_unwarp(img, nx, ny, mtx, dist)\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))\nf.tight_layout()\nax1.imshow(img)\nax1.set_title(\'Original Image\', fontsize=50)\nax2.imshow(top_down)\nax2.set_title(\'Undistorted and Warped Image\', fontsize=50)\nplt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)\n'

Solution to Undistort and Transform quiz:

These steps will all be useful when you get to the project at the end of this section.

First off, we defined a function for you, corners_unwarp(). The function accepts an image and our previously calculated values for the camera matrix, mtx, and distortion coefficients, dist.

Then you had to implement the function.

Here's how I implemented mine:

In [13]:
"""
# Define a function that takes an image, number of x and y points, 
# camera matrix and distortion coefficients
def corners_unwarp(img, nx, ny, mtx, dist):
    # Use the OpenCV undistort() function to remove distortion
    undist = cv2.undistort(img, mtx, dist, None, mtx)
    # Convert undistorted image to grayscale
    gray = cv2.cvtColor(undist, cv2.COLOR_BGR2GRAY)
    # Search for corners in the grayscaled image
    ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)

    if ret == True:
        # If we found corners, draw them! (just for fun)
        cv2.drawChessboardCorners(undist, (nx, ny), corners, ret)
        # Choose offset from image corners to plot detected corners
        # This should be chosen to present the result at the proper aspect ratio
        # My choice of 100 pixels is not exact, but close enough for our purpose here
        offset = 100 # offset for dst points
        # Grab the image shape
        img_size = (gray.shape[1], gray.shape[0])

        # For source points I'm grabbing the outer four detected corners
        src = np.float32([corners[0], corners[nx-1], corners[-1], corners[-nx]])
        # For destination points, I'm arbitrarily choosing some points to be
        # a nice fit for displaying our warped result 
        # again, not exact, but close enough for our purposes
        dst = np.float32([[offset, offset], [img_size[0]-offset, offset], 
                                     [img_size[0]-offset, img_size[1]-offset], 
                                     [offset, img_size[1]-offset]])
        # Given src and dst points, calculate the perspective transform matrix
        M = cv2.getPerspectiveTransform(src, dst)
        # Warp the image using OpenCV warpPerspective()
        warped = cv2.warpPerspective(undist, M, img_size)

    # Return the resulting image and matrix
    return warped, M
"""
Out[13]:
"\n# Define a function that takes an image, number of x and y points, \n# camera matrix and distortion coefficients\ndef corners_unwarp(img, nx, ny, mtx, dist):\n    # Use the OpenCV undistort() function to remove distortion\n    undist = cv2.undistort(img, mtx, dist, None, mtx)\n    # Convert undistorted image to grayscale\n    gray = cv2.cvtColor(undist, cv2.COLOR_BGR2GRAY)\n    # Search for corners in the grayscaled image\n    ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)\n\n    if ret == True:\n        # If we found corners, draw them! (just for fun)\n        cv2.drawChessboardCorners(undist, (nx, ny), corners, ret)\n        # Choose offset from image corners to plot detected corners\n        # This should be chosen to present the result at the proper aspect ratio\n        # My choice of 100 pixels is not exact, but close enough for our purpose here\n        offset = 100 # offset for dst points\n        # Grab the image shape\n        img_size = (gray.shape[1], gray.shape[0])\n\n        # For source points I'm grabbing the outer four detected corners\n        src = np.float32([corners[0], corners[nx-1], corners[-1], corners[-nx]])\n        # For destination points, I'm arbitrarily choosing some points to be\n        # a nice fit for displaying our warped result \n        # again, not exact, but close enough for our purposes\n        dst = np.float32([[offset, offset], [img_size[0]-offset, offset], \n                                     [img_size[0]-offset, img_size[1]-offset], \n                                     [offset, img_size[1]-offset]])\n        # Given src and dst points, calculate the perspective transform matrix\n        M = cv2.getPerspectiveTransform(src, dst)\n        # Warp the image using OpenCV warpPerspective()\n        warped = cv2.warpPerspective(undist, M, img_size)\n\n    # Return the resulting image and matrix\n    return warped, M\n"

Pass in img and set the parameter orient as 'x' or 'y' to take either the x or y gradient. Set min_thresh, and max_thresh to specify the range to select for binary output. You can use exclusive (<, >) or inclusive (<=, >=) thresholding.

NOTE: Your output should be an array of the same size as the input image. The output array elements should be 1 where gradients were in the threshold range, and 0 everywhere else. As usual, if you run into any errors as you run your code, please refer to the Examples of Useful Code section in the previous video and make sure that your code syntax matches up!

In [14]:
"""
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pickle


# Read in an image and grayscale it
image = mpimg.imread('signs_vehicles_xygrad.png')

# Define a function that applies Sobel x or y, 
# then takes an absolute value and applies a threshold.
# Note: calling your function with orient='x', thresh_min=5, thresh_max=100
# should produce output like the example image shown above this quiz.
def abs_sobel_thresh(img, orient='x', thresh_min=0, thresh_max=255):
    
    # Apply the following steps to img
    # 1) Convert to grayscale
    # 2) Take the derivative in x or y given orient = 'x' or 'y'
    # 3) Take the absolute value of the derivative or gradient
    # 4) Scale to 8-bit (0 - 255) then convert to type = np.uint8
    # 5) Create a mask of 1's where the scaled gradient magnitude 
            # is > thresh_min and < thresh_max
    # 6) Return this mask as your binary_output image
    binary_output = np.copy(img) # Remove this line
    return binary_output
    
# Run the function
grad_binary = abs_sobel_thresh(image, orient='x', thresh_min=20, thresh_max=100)
# Plot the result
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(image)
ax1.set_title('Original Image', fontsize=50)
ax2.imshow(grad_binary, cmap='gray')
ax2.set_title('Thresholded Gradient', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
"""
Out[14]:
"\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport pickle\n\n\n# Read in an image and grayscale it\nimage = mpimg.imread('signs_vehicles_xygrad.png')\n\n# Define a function that applies Sobel x or y, \n# then takes an absolute value and applies a threshold.\n# Note: calling your function with orient='x', thresh_min=5, thresh_max=100\n# should produce output like the example image shown above this quiz.\ndef abs_sobel_thresh(img, orient='x', thresh_min=0, thresh_max=255):\n    \n    # Apply the following steps to img\n    # 1) Convert to grayscale\n    # 2) Take the derivative in x or y given orient = 'x' or 'y'\n    # 3) Take the absolute value of the derivative or gradient\n    # 4) Scale to 8-bit (0 - 255) then convert to type = np.uint8\n    # 5) Create a mask of 1's where the scaled gradient magnitude \n            # is > thresh_min and < thresh_max\n    # 6) Return this mask as your binary_output image\n    binary_output = np.copy(img) # Remove this line\n    return binary_output\n    \n# Run the function\ngrad_binary = abs_sobel_thresh(image, orient='x', thresh_min=20, thresh_max=100)\n# Plot the result\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))\nf.tight_layout()\nax1.imshow(image)\nax1.set_title('Original Image', fontsize=50)\nax2.imshow(grad_binary, cmap='gray')\nax2.set_title('Thresholded Gradient', fontsize=50)\nplt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)\n"
In [15]:
# Define a function that takes an image, gradient orientation,
# and threshold min / max values.
def abs_sobel_thresh(img, orient='x', thresh_min=0, thresh_max=255):
    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Apply x or y gradient with the OpenCV Sobel() function
    # and take the absolute value
    if orient == 'x':
        abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0))
    if orient == 'y':
        abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1))
    # Rescale back to 8 bit integer
    scaled_sobel = np.uint8(255*abs_sobel/np.max(abs_sobel))
    # Create a copy and apply the threshold
    binary_output = np.zeros_like(scaled_sobel)
    # Here I'm using inclusive (>=, <=) thresholds, but exclusive is ok too
    binary_output[(scaled_sobel >= thresh_min) & (scaled_sobel <= thresh_max)] = 1

    # Return the result
    return binary_output

Magnitude of the Gradient

In [16]:
"""
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pickle


# Read in an image
image = mpimg.imread('signs_vehicles_xygrad.png')

# Define a function that applies Sobel x and y, 
# then computes the magnitude of the gradient
# and applies a threshold
def mag_thresh(img, sobel_kernel=3, mag_thresh=(0, 255)):
    
    # Apply the following steps to img
    # 1) Convert to grayscale
    # 2) Take the gradient in x and y separately
    # 3) Calculate the magnitude 
    # 4) Scale to 8-bit (0 - 255) and convert to type = np.uint8
    # 5) Create a binary mask where mag thresholds are met
    # 6) Return this mask as your binary_output image
    binary_output = np.copy(img) # Remove this line
    return binary_output
    
# Run the function
mag_binary = mag_thresh(image, sobel_kernel=3, mag_thresh=(30, 100))
# Plot the result
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(image)
ax1.set_title('Original Image', fontsize=50)
ax2.imshow(mag_binary, cmap='gray')
ax2.set_title('Thresholded Magnitude', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
"""
Out[16]:
"\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport pickle\n\n\n# Read in an image\nimage = mpimg.imread('signs_vehicles_xygrad.png')\n\n# Define a function that applies Sobel x and y, \n# then computes the magnitude of the gradient\n# and applies a threshold\ndef mag_thresh(img, sobel_kernel=3, mag_thresh=(0, 255)):\n    \n    # Apply the following steps to img\n    # 1) Convert to grayscale\n    # 2) Take the gradient in x and y separately\n    # 3) Calculate the magnitude \n    # 4) Scale to 8-bit (0 - 255) and convert to type = np.uint8\n    # 5) Create a binary mask where mag thresholds are met\n    # 6) Return this mask as your binary_output image\n    binary_output = np.copy(img) # Remove this line\n    return binary_output\n    \n# Run the function\nmag_binary = mag_thresh(image, sobel_kernel=3, mag_thresh=(30, 100))\n# Plot the result\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))\nf.tight_layout()\nax1.imshow(image)\nax1.set_title('Original Image', fontsize=50)\nax2.imshow(mag_binary, cmap='gray')\nax2.set_title('Thresholded Magnitude', fontsize=50)\nplt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)\n"
In [17]:
# Define a function to return the magnitude of the gradient
# for a given sobel kernel size and threshold values
def mag_thresh(img, sobel_kernel=3, mag_thresh=(0, 255)):
    # Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Take both Sobel x and y gradients
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)
    # Calculate the gradient magnitude
    gradmag = np.sqrt(sobelx**2 + sobely**2)
    # Rescale to 8 bit
    scale_factor = np.max(gradmag)/255 
    gradmag = (gradmag/scale_factor).astype(np.uint8) 
    # Create a binary image of ones where threshold is met, zeros otherwise
    binary_output = np.zeros_like(gradmag)
    binary_output[(gradmag >= mag_thresh[0]) & (gradmag <= mag_thresh[1])] = 1

    # Return the binary image
    return binary_output
In [18]:
test_img = mpimg.imread('./issue_images/org_video_image_20171217_10_22_06.jpg')
test_output = mag_thresh(test_img)
show_two_images(test_img, test_output, title2="Magnitude Image")

Direction of the Gradient

When you play around with the thresholding for the gradient magnitude in the previous exercise, you find what you might expect, namely, that it picks up the lane lines well, but with a lot of other stuff detected too. Gradient magnitude is at the heart of Canny edge detection, and is why Canny works well for picking up all edges.

In the case of lane lines, we're interested only in edges of a particular orientation. So now we will explore the direction, or orientation, of the gradient.

The direction of the gradient is simply the inverse tangent (arctangent) of the y gradient divided by the x gradient:

arctan(sobel ​y ​​ /sobel ​x ​​ ).

Each pixel of the resulting image contains a value for the angle of the gradient away from horizontal in units of radians, covering a range of −π/2 to π/2. An orientation of 0 implies a horizontal line and orientations of +/−π/2 imply vertical lines.

In this next exercise, you'll write a function to compute the direction of the gradient and apply a threshold. The direction of the gradient is much noisier than the gradient magnitude, but you should find that you can pick out particular features by orientation.

Steps to take in this exercise: Fill out the function in the editor below to return a thresholded absolute value of the gradient direction. Use Boolean operators, again with exclusive (<, >) or inclusive (<=, >=) thresholds. Test that your function returns output similar to the example below for sobel_kernel=15, thresh=(0.7, 1.3).

In [19]:
"""
mport numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pickle


# Read in an image
image = mpimg.imread('signs_vehicles_xygrad.png')

# Define a function that applies Sobel x and y, 
# then computes the direction of the gradient
# and applies a threshold.
def dir_threshold(img, sobel_kernel=3, thresh=(0, np.pi/2)):
    
    # Apply the following steps to img
    # 1) Convert to grayscale
    # 2) Take the gradient in x and y separately
    # 3) Take the absolute value of the x and y gradients
    # 4) Use np.arctan2(abs_sobely, abs_sobelx) to calculate the direction of the gradient 
    # 5) Create a binary mask where direction thresholds are met
    # 6) Return this mask as your binary_output image
    binary_output = np.copy(img) # Remove this line
    return binary_output
    
# Run the function
dir_binary = dir_threshold(image, sobel_kernel=15, thresh=(0.7, 1.3))
# Plot the result
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))
f.tight_layout()
ax1.imshow(image)
ax1.set_title('Original Image', fontsize=50)
ax2.imshow(dir_binary, cmap='gray')
ax2.set_title('Thresholded Grad. Dir.', fontsize=50)
plt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)
"""
Out[19]:
"\nmport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport pickle\n\n\n# Read in an image\nimage = mpimg.imread('signs_vehicles_xygrad.png')\n\n# Define a function that applies Sobel x and y, \n# then computes the direction of the gradient\n# and applies a threshold.\ndef dir_threshold(img, sobel_kernel=3, thresh=(0, np.pi/2)):\n    \n    # Apply the following steps to img\n    # 1) Convert to grayscale\n    # 2) Take the gradient in x and y separately\n    # 3) Take the absolute value of the x and y gradients\n    # 4) Use np.arctan2(abs_sobely, abs_sobelx) to calculate the direction of the gradient \n    # 5) Create a binary mask where direction thresholds are met\n    # 6) Return this mask as your binary_output image\n    binary_output = np.copy(img) # Remove this line\n    return binary_output\n    \n# Run the function\ndir_binary = dir_threshold(image, sobel_kernel=15, thresh=(0.7, 1.3))\n# Plot the result\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(24, 9))\nf.tight_layout()\nax1.imshow(image)\nax1.set_title('Original Image', fontsize=50)\nax2.imshow(dir_binary, cmap='gray')\nax2.set_title('Thresholded Grad. Dir.', fontsize=50)\nplt.subplots_adjust(left=0., right=1, top=0.9, bottom=0.)\n"
In [20]:
# Define a function to threshold an image for a given range and Sobel kernel
"""
def dir_threshold(img, sobel_kernel=3, thresh=(0, np.pi/2)):
    # Grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Calculate the x and y gradients
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)
    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)
    # Take the absolute value of the gradient direction, 
    # apply a threshold, and create a binary image result
    absgraddir = np.arctan2(np.absolute(sobely), np.absolute(sobelx))
    binary_output =  np.zeros_like(absgraddir)
    binary_output[(absgraddir >= thresh[0]) & (absgraddir <= thresh[1])] = 1

    # Return the binary image
    return binary_output
"""
Out[20]:
'\ndef dir_threshold(img, sobel_kernel=3, thresh=(0, np.pi/2)):\n    # Grayscale\n    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n    # Calculate the x and y gradients\n    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)\n    sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)\n    # Take the absolute value of the gradient direction, \n    # apply a threshold, and create a binary image result\n    absgraddir = np.arctan2(np.absolute(sobely), np.absolute(sobelx))\n    binary_output =  np.zeros_like(absgraddir)\n    binary_output[(absgraddir >= thresh[0]) & (absgraddir <= thresh[1])] = 1\n\n    # Return the binary image\n    return binary_output\n'

Combining Thresholds

If you play around with the thresholds in the last exercise, you'll find that you can start to identify the lane lines by gradient direction alone by setting the threshold around thresh = (0.7, 1.3), but there's still a lot of noise in the resulting image.

Now consider how you can use various aspects of your gradient measurements (x, y, magnitude, direction) to isolate lane-line pixels. Specifically, think about how you can use thresholds of the x and y gradients, the overall gradient magnitude, and the gradient direction to focus on pixels that are likely to be part of the lane lines. Challenge: In the project at the end of this section, you'll want to experiment with thresholding various aspects of the gradient, so now would be a great time to start coding it up on your local machine! Grab the image we've been working with for the last three quizzes here (or a smaller jpg file here).

Combine the selection thresholds from the last 3 quizzes to write a piece of code like the following, where you can play with various thresholds and see the output.

In [21]:
def abs_sobel_thresh(img, orient='x', sobel_kernel=3, thresh=(0, 255)):
    # Calculate directional gradient
    # Apply threshold
    return grad_binary

def mag_thresh(image, sobel_kernel=3, mag_thresh=(0, 255)):
    # Calculate gradient magnitude
    # Apply threshold
    return mag_binary

def dir_threshold(image, sobel_kernel=3, thresh=(0, np.pi/2)):
    # Calculate gradient direction
    # Apply threshold
    return dir_binary

# Choose a Sobel kernel size
ksize = 3 # Choose a larger odd number to smooth gradient measurements

# Apply each of the thresholding functions
#gradx = abs_sobel_thresh(image, orient='x', sobel_kernel=ksize, thresh=(0, 255))
#grady = abs_sobel_thresh(image, orient='y', sobel_kernel=ksize, thresh=(0, 255))
#mag_binary = mag_thresh(image, sobel_kernel=ksize, mag_thresh=(0, 255))
#dir_binary = dir_threshold(image, sobel_kernel=ksize, thresh=(0, np.pi/2))

Try different combinations and see what you get.

For example, here is a selection for pixels where both the x and y gradients meet the threshold criteria, or the gradient magnitude and direction are both within their threshold values.

In [22]:
#combined = np.zeros_like(dir_binary)
#combined[((gradx == 1) & (grady == 1)) | ((mag_binary == 1) & (dir_binary == 1))] = 1

Color and Gradient

Now it's time to combine what you know about color and gradient thresholding to get the best of both worlds. Here's an example of how that might look: At this point, it's okay to detect edges around trees or cars because these lines can be mostly filtered out by applying a mask to the image and essentially cropping out the area outside of the lane lines. It's most important that you reliably detect different colors of lane lines under varying degrees of daylight and shadow.

You can clearly see which parts of the lane lines were detected by the gradient threshold and which parts were detected by the color threshold by stacking the channels and seeing the individual components. You can create a binary combination of these two images to map out where either the color or gradient thresholds were met. Here's what that looks like in code:

In [23]:
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg


# Edit this function to create your own pipeline.
def pipeline_thresh(img, s_thresh=(170, 255), sx_thresh=(20, 100)):
    img = np.copy(img)
    # Convert to HLS color space and separate the V channel
    hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS).astype(np.float)
    l_channel = hls[:,:,1]
    s_channel = hls[:,:,2]
    
    # Grayscale image
    # NOTE: we already saw that standard grayscaling lost color information for the lane lines
    # Explore gradients in other colors spaces / color channels to see what might work better
    gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

    # Sobel x
    #sobelx = cv2.Sobel(l_channel, cv2.CV_64F, 1, 0) # Take the derivative in x
    sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0) # Take the derivative in x
    
    abs_sobelx = np.absolute(sobelx) # Absolute x derivative to accentuate lines away from horizontal
    scaled_sobel = np.uint8(255*abs_sobelx/np.max(abs_sobelx))
    
    # Threshold x gradient
    sxbinary = np.zeros_like(scaled_sobel)
    sxbinary[(scaled_sobel >= sx_thresh[0]) & (scaled_sobel <= sx_thresh[1])] = 1
    
    # Threshold color channel
    s_binary = np.zeros_like(s_channel)
    s_binary[(s_channel >= s_thresh[0]) & (s_channel <= s_thresh[1])] = 1
    # Stack each channel
    # Note color_binary[:, :, 0] is all 0s, effectively an all black image. It might
    # be beneficial to replace this channel with something else.
    color_binary = np.dstack(( np.zeros_like(sxbinary), sxbinary, s_binary)) * 255
    
    # Combine the two binary thresholds
    combined_binary = np.zeros_like(sxbinary)
    combined_binary[(s_binary == 1) | (sxbinary == 1)] = 1
    #combined_binary[(s_binary == 1)] = 1

    return combined_binary
    #return color_binary
    
    #return gray
    
In [24]:
#image = mpimg.imread('./test_images/test5.jpg')
test_image = mpimg.imread('./test_images/straight_lines1.jpg')

image_threshed = pipeline_thresh(test_image)

show_two_images(test_image, image_threshed, title2="Thresh Pipeline Result")
In [25]:
test_img = mpimg.imread('./issue_images/org_video_image_20171217_10_22_06.jpg')
test_output = pipeline_thresh(test_img, s_thresh=(170, 255), sx_thresh=(5, 100))
show_two_images(test_img, test_output, title2="Magnitude Image")
In [26]:
undistorted = cal_undistort(test_image, objpoints, imgpoints)
show_two_images(test_image, undistorted, title2="Undistorted Image")

Warp

In [27]:
Y_TOP = 435#440
Y_BTM = 668

X_CTR = 640#640 = 1280/2

X_TOP_WDT = 48#45#50#55#65#50#50#60#60
X_BTM_WDT = 1000#1280#1000#1000#900#850

# less space is used
Y_TOP = 450#435#440
X_TOP_WDT = 120#48#45#50#55#65#50#50#60#60


TOP_LEFT = (X_CTR - X_TOP_WDT/2 , Y_TOP)
TOP_RIGHT = (X_CTR + X_TOP_WDT/2, Y_TOP)
BTM_LEFT = (X_CTR - X_BTM_WDT/2 , Y_BTM)
BTM_RIGHT = (X_CTR + X_BTM_WDT/2, Y_BTM)

SRC_TRAPEZOID_ORG_ORDR = [TOP_LEFT, TOP_RIGHT, BTM_RIGHT, BTM_LEFT]
#SRC_TRAPEZOID_WRP = [TOP_LEFT, TOP_RIGHT, BTM_LEFT, BTM_RIGHT]
In [28]:
def pipeline_warp(image, offsetX = 50, offsetY = 0):
    offset = 100 # offset for dst points
    # Grab the image shape
    img_size = (image.shape[1], image.shape[0])
    w = img_size[1]
    h = img_size[1]

    offsetX = 30 # test
    
    src = np.float32(SRC_TRAPEZOID_ORG_ORDR)#SRC_RECTANGLE)
    #error: ..\..\..\modules\imgproc\src\imgwarp.cpp:6101: error: (-215) _src.total() > 0 in function cv::warpPerspective
    #src = np.float32([corners[0],corners[7],corners[40],corners[47]])#([[,],[,],[,],[,]])
    # c) define 4 destination points dst = np.float32([[,],[,],[,],[,]])
    # For destination points, I'm arbitrarily choosing some points to be
    # a nice fit for displaying our warped result 
    # again, not exact, but close enough for our purposes
    #dst = np.float32([[offset, offset], [img_size[0]-offset, offset], 
    #                     [img_size[0]-offset, img_size[1]-offset], 
    #                     [offset, img_size[1]-offset]])
    
    #dst = np.float32([[offsetX, offsetY], [w - offsetX, offsetY], 
    #                 [offsetX, h - offsetY], [w - offsetX, h - offsetY]])

    dst = np.float32([[offsetX, offsetY], [w - offsetX, offsetY], 
                      [w - offsetX, h - offsetY],
                      [offsetX, h - offsetY]])
        
    #dst = np.float32([[,],[,],[,],[,]])
    # d) use cv2.getPerspectiveTransform() to get M, the transform matrix
    M = cv2.getPerspectiveTransform(src, dst)
    # e) use cv2.warpPerspective() to warp your image to a top-down view
    #warped = cv2.warpPerspective(img, M, img_size, flags=cv2.INTER_LINEAR)
    
    warped = cv2.warpPerspective(image,M,(h, w))
    
    Minv = cv2.getPerspectiveTransform(dst, src)

    return warped, M, Minv
In [29]:
#test_img = mpimg.imread('./test_images/straight_lines1.jpg')
test_img = mpimg.imread('./test_images/test1.jpg')
image_threshed = pipeline_thresh(test_img)
image_warped, M, Minv = pipeline_warp(image_threshed)
show_two_images(test_img, image_threshed, title2="Binary Image")
show_two_images(test_img, image_warped, title2="Warped Image")

Finding the Lines

Tracking

After you've tuned your pipeline on test images, you'll run on a video stream, just like in the first project. In this case, however, you're going to keep track of things like where your last several detections of the lane lines were and what the curvature was, so you can properly treat new detections. To do this, it's useful to define a Line() class to keep track of all the interesting parameters you measure from frame to frame. Here's an example:

You can create an instance of the Line() class for the left and right lane lines to keep track of recent detections and to perform sanity checks.

In [30]:
# Define a class to receive the characteristics of each line detection
class Line():
    def __init__(self):
        # was the line detected in the last iteration?
        self.detected = False  
        # x values of the last n fits of the line
        self.recent_xfitted = [] 
        
        #average x values of the fitted line over the last n iterations
        self.bestx = None     
        #polynomial coefficients averaged over the last n iterations
        self.best_fit = None 
        
        #polynomial coefficients for the most recent fit
        self.current_fit = [np.array([False])]  
        self.prev_fit = [np.array([False])]  
        
        #radius of curvature of the line in some units
        self.radius_of_curvature = None 
        #distance in meters of vehicle center from the line
        self.line_base_pos = None 
        
        #difference in fit coefficients between last and new fits
        self.diffs = np.array([0,0,0], dtype='float') 
        
        #x values for detected line pixels
        self.allx = None  
        #y values for detected line pixels
        self.ally = None

    def calc_diffs():
        self.diffs[0] = self.current_fit[0] - self.prev_fit[0]
        self.diffs[1] = self.current_fit[1] - self.prev_fit[1]
        self.diffs[2] = self.current_fit[2] - self.prev_fit[2]
        
    def update_average_and_best(self):
        #average x values of the fitted line over the last n iterations
        self.bestx = None
        #polynomial coefficients averaged over the last n iterations
        self.best_fit = None 

    def compare_last_and_recent(self):
        #difference in fit coefficients between last and new fits
        self.diffs = np.array([0,0,0], dtype='float') 

    def add_recent_data(self, current_fit, detected_x, detected_y):
    
        # was the line detected in the last iteration?
        #self.detected = detected  
        
        #polynomial coefficients for the most recent fit
        self.current_fit = current_fit#[np.array([False])]  
        
        # x values of the last n fits of the line
        self.recent_xfitted.append(current_fit)# = [] #?
        
        #x values for detected line pixels
        self.allx = detected_x #? None  
        #y values for detected line pixels
        self.ally = detected_y #?  None
In [31]:
# Assuming you have created a warped binary image called "binary_warped"
def find_lines(binary_warped):

    # Choose the number of sliding windows
    nwindows = 9
    # Set the width of the windows +/- margin
    margin = 100
    #margin = 150
    # Set minimum number of pixels found to recenter window
    minpix = 50
    
    # Take a histogram of the bottom half of the image
    #histogram = np.sum(binary_warped[binary_warped.shape[0]/2:,:], axis=0)
    histogram = np.sum(binary_warped[np.int(binary_warped.shape[0]/2):,:], axis=0)

    # Create an output image to draw on and  visualize the result
    out_img = np.dstack((binary_warped, binary_warped, binary_warped))*255
    # Find the peak of the left and right halves of the histogram
    # These will be the starting point for the left and right lines
    midpoint = np.int(histogram.shape[0]/2)
    leftx_base = np.argmax(histogram[:midpoint])
    rightx_base = np.argmax(histogram[midpoint:]) + midpoint

    # Set height of windows
    window_height = np.int(binary_warped.shape[0]/nwindows)
    # Identify the x and y positions of all nonzero pixels in the image
    nonzero = binary_warped.nonzero()
    nonzeroy = np.array(nonzero[0])
    nonzerox = np.array(nonzero[1])
    # Current positions to be updated for each window
    leftx_current = leftx_base
    rightx_current = rightx_base

    # Create empty lists to receive left and right lane pixel indices
    left_lane_inds = []
    right_lane_inds = []

    # Step through the windows one by one
    right_stop = False
    left_stop = False
    for window in range(nwindows):
        # Identify window boundaries in x and y (and right and left)
        win_y_low = binary_warped.shape[0] - (window+1)*window_height
        win_y_high = binary_warped.shape[0] - window*window_height
        win_xleft_low = leftx_current - margin
        win_xleft_high = leftx_current + margin
        win_xright_low = rightx_current - margin
        win_xright_high = rightx_current + margin
        # Draw the windows on the visualization image
        cv2.rectangle(out_img,(win_xleft_low,win_y_low),(win_xleft_high,win_y_high),
        (0,255,0), 2) 
        cv2.rectangle(out_img,(win_xright_low,win_y_low),(win_xright_high,win_y_high),
        #(0,255,0), 2) 
        (0,0,255), 2) 
        # Identify the nonzero pixels in x and y within the window
        good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
        (nonzerox >= win_xleft_low) &  (nonzerox < win_xleft_high)).nonzero()[0]
        
        good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
        (nonzerox >= win_xright_low) &  (nonzerox < win_xright_high)).nonzero()[0]
        # Append these indices to the lists
        ##if left_stop == False:
        left_lane_inds.append(good_left_inds)
        ##if right_stop == False:
        right_lane_inds.append(good_right_inds)
        # If you found > minpix pixels, recenter next window on their mean position
        if len(good_left_inds) > minpix:
            leftx_current = np.int(np.mean(nonzerox[good_left_inds]))
        if len(good_right_inds) > minpix:        
            rightx_current = np.int(np.mean(nonzerox[good_right_inds]))
        
        # If 
        ##if (len(nonzerox[good_left_inds]) < 1 and window > nwindows//2) :
        ##    left_stop = True
        ##if (len(nonzerox[good_right_inds]) < 1 and window > nwindows//2) :
        ##    right_stop = True
        #print(len(nonzerox[good_left_inds]), nwindows//2, window,( window > nwindows//2) )

    # Concatenate the arrays of indices
    left_lane_inds = np.concatenate(left_lane_inds)
    right_lane_inds = np.concatenate(right_lane_inds)

    # Extract left and right line pixel positions
    leftx = nonzerox[left_lane_inds]
    lefty = nonzeroy[left_lane_inds] 
    rightx = nonzerox[right_lane_inds]
    righty = nonzeroy[right_lane_inds] 

    # Fit a second order polynomial to each
    left_fit = np.polyfit(lefty, leftx, 2)
    right_fit = np.polyfit(righty, rightx, 2)

    right_line = Line()
    left_line = Line()
    right_line.update_average_and_best()
    right_line.add_recent_data(right_fit, rightx, righty)
    left_line.add_recent_data(left_fit, leftx, lefty)
    
    # was the line detected in the last iteration?
    right_line.detected = False  
    # x values of the last n fits of the line
    right_line.recent_xfitted = [] 
    #average x values of the fitted line over the last n iterations
    right_line.bestx = None     
    #polynomial coefficients averaged over the last n iterations
    right_line.best_fit = None  
    #polynomial coefficients for the most recent fit
    right_line.current_fit = right_fit #[np.array([False])]  
    #radius of curvature of the line in some units
    right_line.radius_of_curvature = None 
    #distance in meters of vehicle center from the line
    right_line.line_base_pos = None 
    #difference in fit coefficients between last and new fits
    right_line.diffs = np.array([0,0,0], dtype='float') 

    
    return left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img

Skip the sliding windows step once you know where the lines are

Now you know where the lines are you have a fit! In the next frame of video you don't need to do a blind search again, but instead you can just search in a margin around the previous line position like this:

In [32]:
# Assume you now have a new warped binary image 
# from the next frame of video (also called "binary_warped")
# It's now much easier to find line pixels!
def find_lines_again(binary_warped, left_fit, right_fit):
    nonzero = binary_warped.nonzero()
    nonzeroy = np.array(nonzero[0])
    nonzerox = np.array(nonzero[1])
    margin = 100
    
    margin = 50
    #margin = 30
    
    left_lane_inds = ((nonzerox > (left_fit[0]*(nonzeroy**2) + left_fit[1]*nonzeroy + 
    left_fit[2] - margin)) & (nonzerox < (left_fit[0]*(nonzeroy**2) + 
    left_fit[1]*nonzeroy + left_fit[2] + margin))) 

    right_lane_inds = ((nonzerox > (right_fit[0]*(nonzeroy**2) + right_fit[1]*nonzeroy + 
    right_fit[2] - margin)) & (nonzerox < (right_fit[0]*(nonzeroy**2) + 
    right_fit[1]*nonzeroy + right_fit[2] + margin)))  

    # Again, extract left and right line pixel positions
    leftx = nonzerox[left_lane_inds]
    lefty = nonzeroy[left_lane_inds] 
    rightx = nonzerox[right_lane_inds]
    righty = nonzeroy[right_lane_inds]
    # Fit a second order polynomial to each
    left_fit = np.polyfit(lefty, leftx, 2)
    right_fit = np.polyfit(righty, rightx, 2)
    # Generate x and y values for plotting
    ploty = np.linspace(0, binary_warped.shape[0]-1, binary_warped.shape[0] )
    left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
    right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
    
    return left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img
In [33]:
# Calculate the new radii of curvature
def calc_radii_of_curvature(fit_cr, y_eval, ym_per_pix):
    curverad = ((1 + (2*fit_cr[0]*y_eval*ym_per_pix + fit_cr[1])**2)**1.5) / np.absolute(2*fit_cr[0])
    return curverad

#left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
#right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])
In [34]:
import numpy as np
import matplotlib.pyplot as plt
# Generate some fake data to represent lane-line pixels
ploty = np.linspace(0, 719, num=720)# to cover same y-range as image
quadratic_coeff = 3e-4 # arbitrary quadratic coefficient
# For each y position generate random x position within +/-50 pix
# of the line base position in each case (x=200 for left, and x=900 for right)
leftx = np.array([200 + (y**2)*quadratic_coeff + np.random.randint(-50, high=51) 
                              for y in ploty])
rightx = np.array([900 + (y**2)*quadratic_coeff + np.random.randint(-50, high=51) 
                                for y in ploty])

leftx = leftx[::-1]  # Reverse to match top-to-bottom in y
rightx = rightx[::-1]  # Reverse to match top-to-bottom in y


# Fit a second order polynomial to pixel positions in each fake lane line
left_fit = np.polyfit(ploty, leftx, 2)
left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
right_fit = np.polyfit(ploty, rightx, 2)
right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]

# Plot up the fake data
mark_size = 3
plt.plot(leftx, ploty, 'o', color='red', markersize=mark_size)
plt.plot(rightx, ploty, 'o', color='blue', markersize=mark_size)
plt.xlim(0, 1280)
plt.ylim(0, 720)
plt.plot(left_fitx, ploty, color='green', linewidth=3)
plt.plot(right_fitx, ploty, color='green', linewidth=3)
plt.gca().invert_yaxis() # to visualize as we do the images

#print("left:", calc_radii_of_curvature(left_fit, y_eval, ym_per_pix))
#print("riht:",calc_radii_of_curvature(right_fit, y_eval, ym_per_pix))
In [35]:
# Define y-value where we want radius of curvature
# I'll choose the maximum y-value, corresponding to the bottom of the image
y_eval = np.max(ploty)
left_curverad = ((1 + (2*left_fit[0]*y_eval + left_fit[1])**2)**1.5) / np.absolute(2*left_fit[0])
right_curverad = ((1 + (2*right_fit[0]*y_eval + right_fit[1])**2)**1.5) / np.absolute(2*right_fit[0])
print(left_curverad, right_curverad)
# Example values: 1926.74 1908.48
1516.34342825 1709.88377305
In [36]:
# Define y-value where we want radius of curvature
# I'll choose the maximum y-value, corresponding to the bottom of the image
def calc_curverad(ploty, fit):
    y_eval = np.max(ploty)
    curverad = ((1 + (2*fit[0]*y_eval + fit[1])**2)**1.5) / np.absolute(2*fit[0])
    return curverad
# Example values: 1926.74 1908.48
In [37]:
# Define conversions in x and y from pixels space to meters
ym_per_pix = 30/720 # meters per pixel in y dimension
xm_per_pix = 3.7/700 # meters per pixel in x dimension

# Fit new polynomials to x,y in world space
left_fit_cr = np.polyfit(ploty*ym_per_pix, leftx*xm_per_pix, 2)
right_fit_cr = np.polyfit(ploty*ym_per_pix, rightx*xm_per_pix, 2)
# Calculate the new radii of curvature
left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])
# Now our radius of curvature is in meters
print(left_curverad, 'm', right_curverad, 'm')
# Example values: 632.1 m    626.2 m
497.307751362 m 561.607844056 m
In [38]:
def calc_radius_in_meter(y_eval, left_fit_cr, right_fit_cr):
    # Define conversions in x and y from pixels space to meters
    ym_per_pix = 30/720 # meters per pixel in y dimension
    xm_per_pix = 3.7/700 # meters per pixel in x dimension

    # Calculate the new radii of curvature
    left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
    right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])
    # Now our radius of curvature is in meters
    return left_curverad, right_curverad
    # Example values: 632.1 m    626.2 m
In [39]:
def calc_vehicle_position(left_fit, right_fit, image):
    #y_btm = 720#
    y_btm = image.shape[0] # Y
    #print("y_btm", y_btm)
    #image_mid = 720//2
    image_mid = image.shape[1]/2 # X
    #print("image_mid", image_mid)
    
    x_left = left_fit[0]*y_btm**2 + left_fit[1]*y_btm + left_fit[2]
    x_right = right_fit[0]*y_btm**2 + right_fit[1]*y_btm + right_fit[2]
    
    #print("x_left", x_left)
    #print("x_right", x_right)
    
    lane_width = x_right - x_left

    x_mid = x_left + (lane_width)//2
    
    #print("x_mid", x_mid)
    
    vehicle_position = image_mid - x_mid
    
    LANE_WIDTH_METER = 3.4
    meter_per_pixel = LANE_WIDTH_METER/lane_width
    vehicle_position_meter = vehicle_position*meter_per_pixel
    
    return vehicle_position_meter#vehicle_position
In [40]:
def put_text(image, text, margin_from_edge = 5, font = cv2.FONT_HERSHEY_PLAIN, font_size = 0.6, color = (255,255,0)):

    #w = image.shape[0]
    #h = image.shape[1]
    
    start_x = margin_from_edge
    start_y = margin_from_edge
    
    cv2.putText(image,text,(start_x,start_y),font, font_size,color)

Visualization

At this point, you're done! But here is how you can visualize the result as well:

In [41]:
def draw_rectangle(img):
    #result = cv.rectangle(img, (10,   50), (50,  150), (255, 0, 0), 3, 4)
    #image = cv2.polylines(img, np.float32(SRC_RECTANGLE), True, (0, 0, 255), 5)
    pts = np.array(SRC_TRAPEZOID_ORG_ORDR, np.int32)
    pts = pts.reshape((-1, 1, 2))
    #pts = np.float32(SRC_RECTANGLE)
    copy = img.copy()
    cv2.polylines(copy, [pts],True,(255,0,0), thickness=2)
    return copy
#X_CENTER = 410
#Y_CENTER = 610
#X_BOTTOM = 660
#X_OFFSET = 5
#Y_OFFSET = 400
In [42]:
class LineProjector():
    def __init__(self, Minv):
        self.Minv = Minv
        
    def project_lines(self, original_image, warped, left_fit, right_fit):
        
        ploty = np.linspace(0, warped.shape[0]-1, warped.shape[0] )
        
        left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
        right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]

        # Create an image to draw the lines on
        warp_zero = np.zeros_like(warped).astype(np.uint8)
        color_warp = np.dstack((warp_zero, warp_zero, warp_zero))

        # Recast the x and y points into usable format for cv2.fillPoly()
        pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))])
        pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, ploty])))])
        pts = np.hstack((pts_left, pts_right))

        # Draw the lane onto the warped blank image
        cv2.fillPoly(color_warp, np.int_([pts]), (0,255, 0))

        # Warp the blank back to original image space using inverse perspective matrix (Minv)
        #newwarp = cv2.warpPerspective(color_warp, self.Minv, (image.shape[1], image.shape[0])) 
        newwarp = cv2.warpPerspective(color_warp, self.Minv, (original_image.shape[1], original_image.shape[0])) 
        # Combine the result with the original image
        result = cv2.addWeighted(original_image, 1, newwarp, 0.3, 0)
        return result
In [43]:
# Generate x and y values for plotting
def visualize_lines(warped, left_fit, right_fit, left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img):
    
    ploty = np.linspace(0, warped.shape[0]-1, warped.shape[0] )
    
    out_img[nonzeroy[left_lane_inds], nonzerox[left_lane_inds]] = [255, 0, 0]
    out_img[nonzeroy[right_lane_inds], nonzerox[right_lane_inds]] = [0, 0, 255]
    
    plt.imshow(out_img)
    
    # Generate x and y values for plotting
    left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
    right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
    plt.plot(left_fitx, ploty, color='yellow')
    plt.plot(right_fitx, ploty, color='yellow')
    
    #print(warped.shape[0], warped.shape[1])

    plt.xlim(0, 1280)
    plt.ylim(720, 0)
In [44]:
test_img = mpimg.imread('./test_images/test2.jpg')
image_threshed = pipeline_thresh(test_img)

binary_warped, M, Minv = pipeline_warp(image_threshed)

left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines(binary_warped)

visualize_lines(binary_warped, left_fit, right_fit, left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img)

#print("left:", calc_radii_of_curvature(left_fit, y_eval, ym_per_pix))
#print("riht:",calc_radii_of_curvature(right_fit, y_eval, ym_per_pix))
In [45]:
test_img = mpimg.imread('./test_images/test2.jpg')
image_threshed = pipeline_thresh(test_img)

binary_warped, M, Minv = pipeline_warp(image_threshed)

left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines_again(binary_warped, left_fit, right_fit)

visualize_lines(binary_warped, left_fit, right_fit, left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img)

Another way to approach the sliding window method is to apply a convolution, which will maximize the number of "hot" pixels in each window. A convolution is the summation of the product of two separate signals, in our case the window template and the vertical slice of the pixel image.

You slide your window template across the image from left to right and any overlapping values are summed together, creating the convolved signal. The peak of the convolved signal is where there was the highest overlap of pixels and the most likely position for the lane marker.

Now let's try using convolutions to find the best window center positions in a thresholded road image. The code below allows you to experiment with using convolutions for a sliding window search function. Go ahead and give it a try.

In [46]:
def window_mask(width, height, img_ref, center,level):
    output = np.zeros_like(img_ref)
    output[int(img_ref.shape[0]-(level+1)*height):int(img_ref.shape[0]-level*height),max(0,int(center-width/2)):min(int(center+width/2),img_ref.shape[1])] = 1
    return output

def find_window_centroids(image, window_width, window_height, margin):
    
    window_centroids = [] # Store the (left,right) window centroid positions per level
    window = np.ones(window_width) # Create our window template that we will use for convolutions
    
    # First find the two starting positions for the left and right lane by using np.sum to get the vertical image slice
    # and then np.convolve the vertical image slice with the window template 
    
    # Sum quarter bottom of image to get slice, could use a different ratio
    l_sum = np.sum(image[int(3*image.shape[0]/4):,:int(image.shape[1]/2)], axis=0)
    l_center = np.argmax(np.convolve(window,l_sum))-window_width/2
    r_sum = np.sum(image[int(3*image.shape[0]/4):,int(image.shape[1]/2):], axis=0)
    r_center = np.argmax(np.convolve(window,r_sum))-window_width/2+int(image.shape[1]/2)
    
    # Add what we found for the first layer
    window_centroids.append((l_center,r_center))
    
    # Go through each layer looking for max pixel locations
    for level in range(1,(int)(image.shape[0]/window_height)):
	    # convolve the window into the vertical slice of the image
	    image_layer = np.sum(image[int(image.shape[0]-(level+1)*window_height):int(image.shape[0]-level*window_height),:], axis=0)
	    conv_signal = np.convolve(window, image_layer)
	    # Find the best left centroid by using past left center as a reference
	    # Use window_width/2 as offset because convolution signal reference is at right side of window, not center of window
	    offset = window_width/2
	    l_min_index = int(max(l_center+offset-margin,0))
	    l_max_index = int(min(l_center+offset+margin,image.shape[1]))
	    l_center = np.argmax(conv_signal[l_min_index:l_max_index])+l_min_index-offset
	    # Find the best right centroid by using past right center as a reference
	    r_min_index = int(max(r_center+offset-margin,0))
	    r_max_index = int(min(r_center+offset+margin,image.shape[1]))
	    r_center = np.argmax(conv_signal[r_min_index:r_max_index])+r_min_index-offset
	    # Add what we found for that layer
	    window_centroids.append((l_center,r_center))

    return window_centroids

def gen_output(window_centroids, warped):
    # If we found any window centers
    output = None
    if len(window_centroids) > 0:

        # Points used to draw all the left and right windows
        l_points = np.zeros_like(warped)
        r_points = np.zeros_like(warped)

        # Go through each level and draw the windows 	
        for level in range(0,len(window_centroids)):
            # Window_mask is a function to draw window areas
            l_mask = window_mask(window_width,window_height,warped,window_centroids[level][0],level)
            r_mask = window_mask(window_width,window_height,warped,window_centroids[level][1],level)
            # Add graphic points from window mask here to total pixels found 
            l_points[(l_points == 255) | ((l_mask == 1) ) ] = 255
            r_points[(r_points == 255) | ((r_mask == 1) ) ] = 125#255

        # Draw the results
        template = np.array(r_points+l_points,np.uint8) # add both left and right window pixels together
        zero_channel = np.zeros_like(template) # create a zero color channel
        template = np.array(cv2.merge((zero_channel,template,zero_channel)),np.uint8) # make window pixels green
        warpage= np.dstack((warped, warped, warped))*255 # making the original road pixels 3 color channels
        output = cv2.addWeighted(warpage, 1, template, 0.5, 0.0) # overlay the orignal road image with window results

    # If no window centers found, just display orginal road image
    else:
        output = np.array(cv2.merge((warped,warped,warped)),np.uint8)
    return output
In [47]:
# Read in a thresholded image
#warped = mpimg.imread('warped_example.jpg')

test_img = mpimg.imread('./test_images/test2.jpg')
image_threshed = pipeline_thresh(test_img)
binary_warped, M, Minv = pipeline_warp(image_threshed)

# window settings
window_width = 50 
window_height = 80 # Break image into 9 vertical layers since image height is 720
margin = 100 # How much to slide left and right for searching

window_centroids = find_window_centroids(binary_warped, window_width, window_height, margin)

output = gen_output(window_centroids, binary_warped)
# Display the final results
plt.imshow(output)
plt.title('window fitting results')
plt.show()
In [48]:
"""
# If we found any window centers
if len(window_centroids) > 0:

    # Points used to draw all the left and right windows
    l_points = np.zeros_like(warped)
    r_points = np.zeros_like(warped)

    # Go through each level and draw the windows 	
    for level in range(0,len(window_centroids)):
        # Window_mask is a function to draw window areas
	    l_mask = window_mask(window_width,window_height,warped,window_centroids[level][0],level)
	    r_mask = window_mask(window_width,window_height,warped,window_centroids[level][1],level)
	    # Add graphic points from window mask here to total pixels found 
	    l_points[(l_points == 255) | ((l_mask == 1) ) ] = 255
	    r_points[(r_points == 255) | ((r_mask == 1) ) ] = 255

    # Draw the results
    template = np.array(r_points+l_points,np.uint8) # add both left and right window pixels together
    zero_channel = np.zeros_like(template) # create a zero color channel
    template = np.array(cv2.merge((zero_channel,template,zero_channel)),np.uint8) # make window pixels green
    warpage= np.dstack((warped, warped, warped))*255 # making the original road pixels 3 color channels
    output = cv2.addWeighted(warpage, 1, template, 0.5, 0.0) # overlay the orignal road image with window results
 
# If no window centers found, just display orginal road image
else:
    output = np.array(cv2.merge((warped,warped,warped)),np.uint8)
"""
Out[48]:
'\n# If we found any window centers\nif len(window_centroids) > 0:\n\n    # Points used to draw all the left and right windows\n    l_points = np.zeros_like(warped)\n    r_points = np.zeros_like(warped)\n\n    # Go through each level and draw the windows \t\n    for level in range(0,len(window_centroids)):\n        # Window_mask is a function to draw window areas\n\t    l_mask = window_mask(window_width,window_height,warped,window_centroids[level][0],level)\n\t    r_mask = window_mask(window_width,window_height,warped,window_centroids[level][1],level)\n\t    # Add graphic points from window mask here to total pixels found \n\t    l_points[(l_points == 255) | ((l_mask == 1) ) ] = 255\n\t    r_points[(r_points == 255) | ((r_mask == 1) ) ] = 255\n\n    # Draw the results\n    template = np.array(r_points+l_points,np.uint8) # add both left and right window pixels together\n    zero_channel = np.zeros_like(template) # create a zero color channel\n    template = np.array(cv2.merge((zero_channel,template,zero_channel)),np.uint8) # make window pixels green\n    warpage= np.dstack((warped, warped, warped))*255 # making the original road pixels 3 color channels\n    output = cv2.addWeighted(warpage, 1, template, 0.5, 0.0) # overlay the orignal road image with window results\n \n# If no window centers found, just display orginal road image\nelse:\n    output = np.array(cv2.merge((warped,warped,warped)),np.uint8)\n'

Processing Each Image

In [49]:
Y_TOP = 450#435#440
Y_BTM = 668

X_CTR = 640#640 = 1280/2

X_TOP_WDT = 120#48#45#50#55#65#50#50#60#60
X_BTM_WDT = 1000#1280#1000#1000#900#850

Y_TOP = 460#435#440
X_TOP_WDT = 150#48#45#50#55#65#50#50#60#60

#X_BTM_WDT = 900

TOP_LEFT = (X_CTR - X_TOP_WDT/2 , Y_TOP)
TOP_RIGHT = (X_CTR + X_TOP_WDT/2, Y_TOP)
BTM_LEFT = (X_CTR - X_BTM_WDT/2 , Y_BTM)
BTM_RIGHT = (X_CTR + X_BTM_WDT/2, Y_BTM)

SRC_TRAPEZOID_ORG_ORDR = [TOP_LEFT, TOP_RIGHT, BTM_RIGHT, BTM_LEFT]
#SRC_TRAPEZOID_WRP = [TOP_LEFT, TOP_RIGHT, BTM_LEFT, BTM_RIGHT]
In [50]:
def show_process_images(image, objpoints, imgpoints, left_fit_prev=None, right_fit_prev=None, sx_thresh=(20, 100)):
    
    #put_text(image, "test")
    #cv2.putText(image,text,(start_x,start_y),font, font_size,color)
    image = cv2.putText(image,"text",(10,10),fontFace = cv2.FONT_HERSHEY_PLAIN, fontScale = 10, color = (255,255,0))
    
    undistorted = cal_undistort(image, objpoints, imgpoints)
    #show_two_images(image, undistorted)
    thresed = pipeline_thresh(undistorted, sx_thresh=sx_thresh)
    #show_two_images(undistorted, thresed)
    binary_warped, M, Minv = pipeline_warp(thresed)
    undistorted_w_line = draw_rectangle(undistorted)

    #show_two_images(undistorted_w_line, binary_warped)
    if not (left_fit_prev==None and right_fit_prev==None):
        left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines_again(binary_warped, left_fit_prev, right_fit_prev)
    else:
        left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines(binary_warped)

    line_projector = LineProjector(Minv)

    #visualize_lines(ploty, left_fit, right_fit, left_lane_inds, right_lane_inds, nonzerox, nonzeroy)

    result = line_projector.project_lines(undistorted_w_line, binary_warped, left_fit, right_fit)
    #result = project_lines(org_image, warped, left_fit, right_fit, ploty, Minv)
    #plt.imshow(result)
    show_two_images(thresed, binary_warped, title1="Original Image", title2="Warped Image")
    empty = None
    
    ploty = np.linspace(0, image.shape[0]-1, image.shape[0] )
    y_eval = np.max(ploty)
    left_curverad, right_curverad = calc_radius_in_meter(y_eval, left_fit, right_fit)
    #print(left_curverad, right_curverad)
    
    vehicle_position = calc_vehicle_position(left_fit, right_fit, binary_warped)
    
    text_radius = "Radius:{} ".format((left_curverad + right_curverad)/2)
    text_position = "Vehicle Position:{} ".format(vehicle_position)
    #put_text(result, text)
    print(text_position)
    cv2.putText(result,text_radius,(50,100),fontFace = cv2.FONT_ITALIC, fontScale = 3, color = (0,0,255))#255,255,255))
    cv2.putText(result,text_position,(50,200),fontFace = cv2.FONT_ITALIC, fontScale = 3, color = (0,255,0))#255,255,255))
    
    show_two_images(result, result)
        
    left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines(binary_warped)
    
    visualize_lines(binary_warped, left_fit, right_fit, left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img)

    return left_fit, right_fit
In [51]:
test_img = mpimg.imread('./test_images/straight_lines1.jpg')
#print(test_img.shape[0])
#print(test_img.shape[1])

show_process_images(test_img, objpoints, imgpoints)
y_btm 720
image_mid 360.0
x_left 126.831095678
x_right 616.809673964
x_mid 370.831095678
Vehicle Position:-0.07515782717252985 
Out[51]:
(array([  1.75148122e-05,   1.39427219e-02,   1.07712657e+02]),
 array([  4.26978875e-05,  -4.98363521e-02,   6.30557263e+02]))
In [52]:
test_img = mpimg.imread('./test_images/test1.jpg')
show_process_images(test_img, objpoints, imgpoints)
y_btm 720
image_mid 360.0
x_left 143.551062857
x_right 633.564677716
x_mid 388.551062857
Vehicle Position:-0.1981039113418875 
Out[52]:
(array([  1.57252064e-04,  -1.68836315e-01,   1.83593740e+02]),
 array([  1.12255570e-05,  -1.43115345e-01,   7.30788397e+02]))
In [53]:
test_img = mpimg.imread('./test_images/test2.jpg')
show_process_images(test_img, objpoints, imgpoints)
y_btm 720
image_mid 360.0
x_left 169.976168875
x_right 648.347762658
x_mid 408.976168875
Vehicle Position:-0.34809544784343893 
Out[53]:
(array([ -1.76637121e-04,   2.81933131e-01,   5.85529986e+01]),
 array([ -1.59462371e-04,   1.96172746e-01,   5.89768678e+02]))
In [54]:
test_img = mpimg.imread('./test_images/test4.jpg')
left_fit_prev, right_fit_prev = show_process_images(test_img, objpoints, imgpoints)
y_btm 720
image_mid 360.0
x_left 157.002799201
x_right 672.377585134
x_mid 414.002799201
Vehicle Position:-0.35626406703627606 

So you can see that your yellow lane detection is not strong at all, since you are able to detect yellows only very close to the car, where the clarity is much better. The approach to better this is to

Try other color spaces. For instance looking at the blue and green channels of the RGB might give you yellow pixels easily (yellow = blue + green right) Try to limit your search based on the expected lane width. This will prevent the weird effects that you see in your final image. In every detection, reinforce the weaker lane (lane with lesser pixels) with the stronger lane by assuming that the two lanes are parallel.

If there are too few pixels detected in a particular lane, just discard it and use the previous lane as the value. One another approach I took was to do a weighted average of the polynomials from previous frames to current one, based on the number of thresholded pixels. So if the current image has a lot of thresholded pixels, then I give the current polynomial a lot of importance, otherwise no. This is a generalization of point 3.

In [55]:
test_img = mpimg.imread('./issue_images/org_video_image_20171217_10_22_06.jpg')
#test_output = pipeline_thresh(test_img, s_thresh=(170, 255), sx_thresh=(5, 100))
show_process_images(test_img, objpoints, imgpoints)#, sx_thresh=(5, 100))
show_process_images(test_img, objpoints, imgpoints,left_fit_prev, right_fit_prev)
y_btm 720
image_mid 360.0
x_left 249.027841237
x_right 403.38029561
x_mid 326.027841237
Vehicle Position:0.7483220157717451 
C:\Anaconda3\envs\carnd-term1\lib\site-packages\ipykernel_launcher.py:15: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.
  from ipykernel import kernelapp as app
y_btm 720
image_mid 360.0
x_left 404.920005731
x_right 715.224579292
x_mid 559.920005731
Vehicle Position:-2.190518855984685 
Out[55]:
(array([  7.00593440e-04,  -6.70527130e-01,   3.68619736e+02]),
 array([  3.38328657e-04,  -5.03670614e-01,   5.90633562e+02]))

Thresholded binary image

  • Apply a distortion correction to raw images.
  • Use color transforms, gradients, etc., to create a thresholded binary image.

Perspective transform to rectify binary image ("birds-eye view")

  • Apply a perspective transform to rectify binary image ("birds-eye view").
  • Detect lane pixels and fit to find the lane boundary.

Lane boundaries and numerical estimation of lane curvature and vehicle position

  • Determine the curvature of the lane and vehicle position with respect to center.
  • Warp the detected lane boundaries back onto the original image.
  • Output visual display of the lane boundaries and numerical estimation of lane curvature and vehicle position.

Tips and Tricks for the Project

Drawing

Once you have a good measurement of the line positions in warped space, it's time to project your measurement back down onto the road! Let's suppose, as in the previous example, you have a warped binary image called warped, and you have fit the lines with a polynomial and have arrays called ploty, left_fitx and right_fitx, which represent the x and y pixel values of the lines. You can then project those lines onto the original image as follows:

In [56]:
"""
org_image = undistorted
line_projector = LineProjector(Minv)
result = line_projector.project_lines(org_image, binary_warped, left_fit, right_fit)
#result = project_lines(org_image, warped, left_fit, right_fit, Minv)
plt.imshow(result)
"""
Out[56]:
'\norg_image = undistorted\nline_projector = LineProjector(Minv)\nresult = line_projector.project_lines(org_image, binary_warped, left_fit, right_fit)\n#result = project_lines(org_image, warped, left_fit, right_fit, Minv)\nplt.imshow(result)\n'
In [57]:
flg_in_process = False
left_fit = None
right_fit = None
count = 0
DIR_ORG_VIDEO_SHOT = "./video_images/"
DIR_CVT_VIDEO_SHOT = "./converted_images/"
ORG_VIDEO_FILE_NAME = "org_video_image_"
CVT_VIDEO_FILE_NAME = "cvt_video_image_"
from PIL import Image
def save_image(image, dirname, filename):
    """save a image file"""    
    filepath = dirname + filename + datetime.now().strftime("%Y%m%d_%H_%M_%S.jpg")
    if not os.path.exists(filepath) :
        Image.fromarray(image).save(filepath)
In [62]:
from datetime import datetime
import os
def video_pipeline(image):

    #save_image(image,DIR_ORG_VIDEO_SHOT, ORG_VIDEO_FILE_NAME)
    
    processed_image = np.copy(image)
    
    # Undistort image (Try)
    processed_image = cal_undistort(processed_image, objpoints, imgpoints)
    
    processed_image = pipeline_thresh(processed_image)
    binary_warped, M, Minv = pipeline_warp(processed_image)
    
    
    if flg_in_process == False:
        left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines(binary_warped)
    else:
        left_fit, right_fit,left_lane_inds, right_lane_inds, nonzerox, nonzeroy, out_img = find_lines_again(binary_warped, left_fit, right_fit)
    #ploty = np.linspace(0, binary_warped.shape[0]-1, binary_warped.shape[0] )
    line_projector = LineProjector(Minv)
    processed_image = line_projector.project_lines(image, binary_warped, left_fit, right_fit)#, ploty, Minv)
    
    #ploty = np.linspace(0, image.shape[0]-1, image.shape[0] )
    #y_eval = np.max(ploty)
    #left_curverad, right_curverad = calc_radius_in_meter(y_eval, left_fit, right_fit)    
    #text = "Radius:{} ".format((left_curverad + right_curverad)/2)
    #cv2.putText(processed_image,text,(50,200),fontFace = cv2.FONT_ITALIC, fontScale = 3, color = (0,0,255))#255,255,255))
    
    vehicle_position = calc_vehicle_position(left_fit, right_fit, binary_warped)
    
    text_radius = "Radius:{} ".format((left_curverad + right_curverad)/2)
    text_position = "Vehicle Position:{} ".format(vehicle_position)
    cv2.putText(processed_image,text_radius,(50,100),fontFace = cv2.FONT_ITALIC, fontScale = 3, color = (0,0,255))#255,255,255))
    cv2.putText(processed_image,text_position,(50,200),fontFace = cv2.FONT_ITALIC, fontScale = 3, color = (0,255,0))#255,255,255))
    
    
    #save_image(processed_image,DIR_CVT_VIDEO_SHOT, CVT_VIDEO_FILE_NAME)
    
    return processed_image # This must be a color image
In [63]:
def process_image(image):
    # NOTE: The output you return should be a color image (3 channel) for processing video below
    # TODO: put your pipeline here,
    # you should return the final output (image where lines are drawn on lanes)
    result = video_pipeline(image)
    return result
In [64]:
# Import everything needed to edit/save/watch video clips
from moviepy.editor import VideoFileClip
from IPython.display import HTML
In [65]:
VIDEO_INPUT = 'challenge_video.mp4'
VIDEO_OUTPUT = 'output_images/challenge_video_output.mp4'
## To speed up the testing process you may want to try your pipeline on a shorter subclip of the video
## To do so add .subclip(start_second,end_second) to the end of the line below
## Where start_second and end_second are integer values representing the start and end of the subclip
## You may also uncomment the following line for a subclip of the first 5 seconds
##clip1 = VideoFileClip("test_videos/solidWhiteRight.mp4").subclip(0,5)
clip1 = VideoFileClip(VIDEO_INPUT)
white_clip = clip1.fl_image(process_image) #NOTE: this function expects color images!!
%time white_clip.write_videofile(VIDEO_OUTPUT, audio=False)
flg_in_process = False
left_fit = None
right_fit = None
y_btm 720
image_mid 360.0
x_left 174.771541366
x_right 609.429676222
x_mid 391.771541366
[MoviePy] >>>> Building video output_images/challenge_video_output.mp4
[MoviePy] Writing video output_images/challenge_video_output.mp4
  0%|                                                                                          | 0/485 [00:00<?, ?it/s]
y_btm 720
image_mid 360.0
x_left 174.771541366
x_right 609.429676222
x_mid 391.771541366
  0%|▏                                                                                 | 1/485 [00:00<07:45,  1.04it/s]
y_btm 720
image_mid 360.0
x_left 166.450520747
x_right 610.691862372
x_mid 388.450520747
  0%|▎                                                                                 | 2/485 [00:01<07:21,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 169.85575834
x_right 609.562997363
x_mid 388.85575834
  1%|▌                                                                                 | 3/485 [00:02<07:04,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 163.776363199
x_right 607.699233232
x_mid 384.776363199
  1%|▋                                                                                 | 4/485 [00:03<06:52,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 166.855560201
x_right 606.2826607
x_mid 385.855560201
  1%|▊                                                                                 | 5/485 [00:04<06:44,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 166.276023138
x_right 604.600577482
x_mid 385.276023138
  1%|█                                                                                 | 6/485 [00:04<06:38,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 166.365395674
x_right 604.369130722
x_mid 385.365395674
  1%|█▏                                                                                | 7/485 [00:05<06:51,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 166.044547031
x_right 604.691496117
x_mid 385.044547031
  2%|█▎                                                                                | 8/485 [00:06<06:47,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 167.795180415
x_right 606.563793848
x_mid 386.795180415
  2%|█▌                                                                                | 9/485 [00:07<06:39,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 179.052949427
x_right 605.52140205
x_mid 392.052949427
  2%|█▋                                                                               | 10/485 [00:08<06:33,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 176.02066057
x_right 606.812128626
x_mid 391.02066057
  2%|█▊                                                                               | 11/485 [00:09<06:29,  1.22it/s]
y_btm 720
image_mid 360.0
x_left -52.1862622721
x_right 608.310364718
x_mid 277.813737728
  2%|██                                                                               | 12/485 [00:10<06:32,  1.20it/s]
y_btm 720
image_mid 360.0
x_left -64.6813366475
x_right 610.42527031
x_mid 272.318663352
  3%|██▏                                                                              | 13/485 [00:10<06:38,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 175.68010817
x_right 610.431074905
x_mid 392.68010817
  3%|██▎                                                                              | 14/485 [00:11<06:53,  1.14it/s]
y_btm 720
image_mid 360.0
x_left -62.6484508116
x_right 609.192672673
x_mid 272.351549188
  3%|██▌                                                                              | 15/485 [00:12<06:40,  1.17it/s]
y_btm 720
image_mid 360.0
x_left -59.6358492893
x_right 609.54542703
x_mid 274.364150711
  3%|██▋                                                                              | 16/485 [00:13<06:32,  1.19it/s]
y_btm 720
image_mid 360.0
x_left -43.6557458471
x_right 611.82648644
x_mid 283.344254153
  4%|██▊                                                                              | 17/485 [00:14<06:27,  1.21it/s]
y_btm 720
image_mid 360.0
x_left -51.348558319
x_right 614.277963538
x_mid 280.651441681
  4%|███                                                                              | 18/485 [00:15<06:22,  1.22it/s]
y_btm 720
image_mid 360.0
x_left -38.7025853745
x_right 616.439582399
x_mid 288.297414625
  4%|███▏                                                                             | 19/485 [00:15<06:20,  1.22it/s]
y_btm 720
image_mid 360.0
x_left -39.9818000228
x_right 618.636047229
x_mid 289.018199977
  4%|███▎                                                                             | 20/485 [00:16<06:28,  1.20it/s]
y_btm 720
image_mid 360.0
x_left -35.2225692402
x_right 615.430373775
x_mid 289.77743076
  4%|███▌                                                                             | 21/485 [00:17<06:47,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 177.692494851
x_right 613.702298793
x_mid 395.692494851
  5%|███▋                                                                             | 22/485 [00:18<06:39,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 171.396855484
x_right 616.604088746
x_mid 393.396855484
  5%|███▊                                                                             | 23/485 [00:19<06:29,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 155.165453023
x_right 615.30404365
x_mid 385.165453023
  5%|████                                                                             | 24/485 [00:20<06:34,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 188.731385252
x_right 612.218969945
x_mid 399.731385252
  5%|████▏                                                                            | 25/485 [00:21<06:26,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 181.683682309
x_right 614.310266078
x_mid 397.683682309
  5%|████▎                                                                            | 26/485 [00:21<06:31,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 204.687273812
x_right 615.434256245
x_mid 409.687273812
  6%|████▌                                                                            | 27/485 [00:22<06:56,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 195.338837878
x_right 612.635697291
x_mid 403.338837878
  6%|████▋                                                                            | 28/485 [00:23<06:49,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 9.88797081957
x_right 614.909278426
x_mid 311.88797082
  6%|████▊                                                                            | 29/485 [00:24<06:39,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 0.958641117759
x_right 620.30502826
x_mid 309.958641118
  6%|█████                                                                            | 30/485 [00:25<06:30,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 188.404085079
x_right 625.416225432
x_mid 406.404085079
  6%|█████▏                                                                           | 31/485 [00:26<06:25,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 185.767179402
x_right 629.704285416
x_mid 406.767179402
  7%|█████▎                                                                           | 32/485 [00:27<06:20,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 187.493058691
x_right 636.48132803
x_mid 411.493058691
  7%|█████▌                                                                           | 33/485 [00:28<06:35,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 213.251146956
x_right 645.567493033
x_mid 429.251146956
  7%|█████▋                                                                           | 34/485 [00:28<06:26,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 203.951416082
x_right 653.422865515
x_mid 427.951416082
  7%|█████▊                                                                           | 35/485 [00:30<07:06,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 180.806164763
x_right 643.40737245
x_mid 411.806164763
  7%|██████                                                                           | 36/485 [00:30<07:01,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 218.533080292
x_right 638.03275448
x_mid 427.533080292
  8%|██████▏                                                                          | 37/485 [00:31<06:49,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 220.271302391
x_right 640.877489645
x_mid 430.271302391
  8%|██████▎                                                                          | 38/485 [00:32<06:33,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 155.917053018
x_right 641.424366537
x_mid 397.917053018
  8%|██████▌                                                                          | 39/485 [00:33<06:55,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 176.43274916
x_right 644.979102586
x_mid 410.43274916
  8%|██████▋                                                                          | 40/485 [00:34<06:40,  1.11it/s]
y_btm 720
image_mid 360.0
x_left -52.3843998283
x_right 644.99012597
x_mid 295.615600172
  8%|██████▊                                                                          | 41/485 [00:35<06:26,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 175.816606973
x_right 643.171487543
x_mid 408.816606973
  9%|███████                                                                          | 42/485 [00:36<06:27,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 182.709705427
x_right 636.238061193
x_mid 408.709705427
  9%|███████▏                                                                         | 43/485 [00:37<06:37,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 185.872878469
x_right 611.173383009
x_mid 397.872878469
  9%|███████▎                                                                         | 44/485 [00:37<06:25,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 177.607811122
x_right 623.798091961
x_mid 400.607811122
  9%|███████▌                                                                         | 45/485 [00:38<06:38,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 191.187199574
x_right 637.008939354
x_mid 413.187199574
  9%|███████▋                                                                         | 46/485 [00:39<06:23,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 180.313716885
x_right 674.763271061
x_mid 427.313716885
 10%|███████▊                                                                         | 47/485 [00:40<06:21,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 161.803494079
x_right 661.572388084
x_mid 410.803494079
 10%|████████                                                                         | 48/485 [00:41<06:20,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 184.016081778
x_right 671.108705429
x_mid 427.016081778
 10%|████████▏                                                                        | 49/485 [00:42<06:14,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 243.266532505
x_right 679.288266007
x_mid 461.266532505
 10%|████████▎                                                                        | 50/485 [00:43<06:11,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 133.066496693
x_right 693.310121707
x_mid 413.066496693
 11%|████████▌                                                                        | 51/485 [00:44<06:32,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 81.3731617607
x_right 700.707789216
x_mid 390.373161761
 11%|████████▋                                                                        | 52/485 [00:45<06:28,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 44.5555087946
x_right 715.675209615
x_mid 379.555508795
 11%|████████▊                                                                        | 53/485 [00:45<06:25,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 40.7437422133
x_right 580.312129056
x_mid 309.743742213
 11%|█████████                                                                        | 54/485 [00:46<06:15,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 51.030723877
x_right 562.575715662
x_mid 306.030723877
 11%|█████████▏                                                                       | 55/485 [00:47<06:11,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 39.1446982951
x_right 562.927610089
x_mid 300.144698295
 12%|█████████▎                                                                       | 56/485 [00:48<06:14,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 30.7162628672
x_right 558.252050114
x_mid 293.716262867
 12%|█████████▌                                                                       | 57/485 [00:49<06:17,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 40.998159187
x_right 519.15402616
x_mid 279.998159187
 12%|█████████▋                                                                       | 58/485 [00:50<06:37,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 248.920054865
x_right 563.947901135
x_mid 405.920054865
 12%|█████████▊                                                                       | 59/485 [00:51<06:37,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 224.430824416
x_right 557.82455076
x_mid 390.430824416
 12%|██████████                                                                       | 60/485 [00:52<06:48,  1.04it/s]
y_btm 720
image_mid 360.0
x_left 237.276858018
x_right 561.190834441
x_mid 398.276858018
 13%|██████████▏                                                                      | 61/485 [00:53<06:40,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 221.99201307
x_right 708.590887874
x_mid 464.99201307
 13%|██████████▎                                                                      | 62/485 [00:54<06:29,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 230.82693616
x_right 628.424663681
x_mid 428.82693616
 13%|██████████▌                                                                      | 63/485 [00:55<06:41,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 124.834935557
x_right 597.966496368
x_mid 360.834935557
 13%|██████████▋                                                                      | 64/485 [00:56<06:38,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 55.0054941228
x_right 558.928754609
x_mid 306.005494123
 13%|██████████▊                                                                      | 65/485 [00:56<06:23,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 46.6173486279
x_right 544.116432185
x_mid 294.617348628
 14%|███████████                                                                      | 66/485 [00:57<06:13,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 280.053257157
x_right 600.007634395
x_mid 439.053257157
 14%|███████████▏                                                                     | 67/485 [00:58<06:09,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 286.108580171
x_right 586.727151989
x_mid 436.108580171
 14%|███████████▎                                                                     | 68/485 [00:59<06:03,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 307.404464758
x_right 580.468977786
x_mid 443.404464758
 14%|███████████▌                                                                     | 69/485 [01:00<06:06,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 258.521157798
x_right 558.26760956
x_mid 407.521157798
 14%|███████████▋                                                                     | 70/485 [01:01<06:34,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 289.273390617
x_right 566.26545099
x_mid 427.273390617
 15%|███████████▊                                                                     | 71/485 [01:02<06:22,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 91.8162569907
x_right 564.555813422
x_mid 327.816256991
 15%|████████████                                                                     | 72/485 [01:03<06:15,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 86.6440715128
x_right 563.348632335
x_mid 324.644071513
 15%|████████████▏                                                                    | 73/485 [01:04<06:05,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 81.0852955485
x_right 565.092258142
x_mid 323.085295548
 15%|████████████▎                                                                    | 74/485 [01:04<06:02,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 90.01979363
x_right 563.7846159
x_mid 326.01979363
 15%|████████████▌                                                                    | 75/485 [01:05<06:00,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 90.5045504222
x_right 539.965962741
x_mid 314.504550422
 16%|████████████▋                                                                    | 76/485 [01:07<06:47,  1.00it/s]
y_btm 720
image_mid 360.0
x_left 86.540569288
x_right 415.841668585
x_mid 250.540569288
 16%|████████████▊                                                                    | 77/485 [01:08<06:34,  1.03it/s]
y_btm 720
image_mid 360.0
x_left 88.216173466
x_right 442.085553418
x_mid 264.216173466
 16%|█████████████                                                                    | 78/485 [01:08<06:18,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 93.0515490987
x_right 567.855445345
x_mid 330.051549099
 16%|█████████████▏                                                                   | 79/485 [01:09<06:09,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 96.5836758622
x_right 515.000980097
x_mid 305.583675862
 16%|█████████████▎                                                                   | 80/485 [01:10<05:58,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 104.778020175
x_right 531.545730178
x_mid 317.778020175
 17%|█████████████▌                                                                   | 81/485 [01:11<05:50,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 96.9583330795
x_right 555.832966846
x_mid 325.958333079
 17%|█████████████▋                                                                   | 82/485 [01:12<06:06,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 87.9431087792
x_right 571.763484768
x_mid 328.943108779
 17%|█████████████▊                                                                   | 83/485 [01:13<05:55,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 87.5804384972
x_right 573.638257043
x_mid 330.580438497
 17%|██████████████                                                                   | 84/485 [01:14<05:48,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 100.255426514
x_right 589.39654137
x_mid 344.255426514
 18%|██████████████▏                                                                  | 85/485 [01:14<05:44,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 104.560091949
x_right 595.834720678
x_mid 349.560091949
 18%|██████████████▎                                                                  | 86/485 [01:15<05:38,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 109.940984439
x_right 571.38418493
x_mid 339.940984439
 18%|██████████████▌                                                                  | 87/485 [01:16<05:36,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 119.716754713
x_right 557.07192273
x_mid 337.716754713
 18%|██████████████▋                                                                  | 88/485 [01:17<05:41,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 121.783213917
x_right 546.111453755
x_mid 333.783213917
 18%|██████████████▊                                                                  | 89/485 [01:18<05:52,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 125.569560639
x_right 510.157615086
x_mid 317.569560639
 19%|███████████████                                                                  | 90/485 [01:19<05:42,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 118.815452558
x_right 455.797871401
x_mid 286.815452558
 19%|███████████████▏                                                                 | 91/485 [01:20<05:37,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 118.661172854
x_right 471.627327793
x_mid 294.661172854
 19%|███████████████▎                                                                 | 92/485 [01:20<05:33,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 127.303165258
x_right 481.390566498
x_mid 304.303165258
 19%|███████████████▌                                                                 | 93/485 [01:21<05:36,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 130.735891966
x_right 501.477281139
x_mid 315.735891966
 19%|███████████████▋                                                                 | 94/485 [01:22<05:32,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 139.387002849
x_right 531.082925955
x_mid 334.387002849
 20%|███████████████▊                                                                 | 95/485 [01:23<05:45,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 126.193505919
x_right 525.392755502
x_mid 325.193505919
 20%|████████████████                                                                 | 96/485 [01:24<05:41,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 138.330617659
x_right 576.242302183
x_mid 356.330617659
 20%|████████████████▏                                                                | 97/485 [01:25<05:33,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 148.025227057
x_right 577.693562155
x_mid 362.025227057
 20%|████████████████▎                                                                | 98/485 [01:26<05:30,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 136.587993895
x_right 574.681428267
x_mid 355.587993895
 20%|████████████████▌                                                                | 99/485 [01:26<05:27,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 160.491940838
x_right 576.863462613
x_mid 368.491940838
 21%|████████████████▍                                                               | 100/485 [01:27<05:24,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 168.082352241
x_right 579.349050576
x_mid 373.082352241
 21%|████████████████▋                                                               | 101/485 [01:28<05:42,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 160.797469623
x_right 580.501861835
x_mid 369.797469623
 21%|████████████████▊                                                               | 102/485 [01:29<05:34,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 157.188337263
x_right 584.507368294
x_mid 370.188337263
 21%|████████████████▉                                                               | 103/485 [01:30<05:29,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 140.501162451
x_right 589.081929586
x_mid 364.501162451
 21%|█████████████████▏                                                              | 104/485 [01:31<05:27,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 127.738362443
x_right 598.277443424
x_mid 362.738362443
 22%|█████████████████▎                                                              | 105/485 [01:32<05:23,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 154.585056336
x_right 589.060803826
x_mid 371.585056336
 22%|█████████████████▍                                                              | 106/485 [01:32<05:20,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 130.374667532
x_right 589.165542064
x_mid 359.374667532
 22%|█████████████████▋                                                              | 107/485 [01:33<05:24,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 130.688107157
x_right 586.969903101
x_mid 358.688107157
 22%|█████████████████▊                                                              | 108/485 [01:34<05:33,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 142.135401433
x_right 590.849452148
x_mid 366.135401433
 22%|█████████████████▉                                                              | 109/485 [01:35<05:26,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 140.35921014
x_right 587.853452079
x_mid 363.35921014
 23%|██████████████████▏                                                             | 110/485 [01:36<05:20,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 140.343045134
x_right 588.544260214
x_mid 364.343045134
 23%|██████████████████▎                                                             | 111/485 [01:37<05:17,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 134.955812764
x_right 588.84999723
x_mid 360.955812764
 23%|██████████████████▍                                                             | 112/485 [01:38<05:15,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 178.717453289
x_right 571.003788369
x_mid 374.717453289
 23%|██████████████████▋                                                             | 113/485 [01:38<05:12,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 176.102496707
x_right 570.06832707
x_mid 372.102496707
 24%|██████████████████▊                                                             | 114/485 [01:39<05:32,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 132.411806172
x_right 588.550000712
x_mid 360.411806172
 24%|██████████████████▉                                                             | 115/485 [01:40<05:23,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 187.438952688
x_right 591.996059127
x_mid 389.438952688
 24%|███████████████████▏                                                            | 116/485 [01:41<05:15,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 184.821601562
x_right 584.740036348
x_mid 383.821601562
 24%|███████████████████▎                                                            | 117/485 [01:42<05:14,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 182.610744421
x_right 592.946401536
x_mid 387.610744421
 24%|███████████████████▍                                                            | 118/485 [01:43<05:09,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 134.490520087
x_right 577.162398469
x_mid 355.490520087
 25%|███████████████████▋                                                            | 119/485 [01:44<05:08,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 109.938759939
x_right 459.513163145
x_mid 283.938759939
 25%|███████████████████▊                                                            | 120/485 [01:45<05:23,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 121.713608949
x_right 523.92846302
x_mid 322.713608949
 25%|███████████████████▉                                                            | 121/485 [01:45<05:18,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 123.211190607
x_right 537.770696713
x_mid 330.211190607
 25%|████████████████████                                                            | 122/485 [01:46<05:13,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 140.5148528
x_right 518.562795705
x_mid 329.5148528
 25%|████████████████████▎                                                           | 123/485 [01:47<05:08,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 144.464495209
x_right 531.282357354
x_mid 337.464495209
 26%|████████████████████▍                                                           | 124/485 [01:48<05:04,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 153.038570822
x_right 551.004365185
x_mid 351.038570822
 26%|████████████████████▌                                                           | 125/485 [01:49<05:00,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 159.364269941
x_right 546.253042344
x_mid 352.364269941
 26%|████████████████████▊                                                           | 126/485 [01:50<05:05,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 165.284068134
x_right 564.198158915
x_mid 364.284068134
 26%|████████████████████▉                                                           | 127/485 [01:51<05:17,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 169.755566657
x_right 571.221259123
x_mid 369.755566657
 26%|█████████████████████                                                           | 128/485 [01:51<05:10,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 172.015023929
x_right 570.50522276
x_mid 371.015023929
 27%|█████████████████████▎                                                          | 129/485 [01:52<05:07,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 175.985433519
x_right 580.55810864
x_mid 377.985433519
 27%|█████████████████████▍                                                          | 130/485 [01:53<05:03,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 172.722531005
x_right 583.924693952
x_mid 377.722531005
 27%|█████████████████████▌                                                          | 131/485 [01:54<04:59,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 167.850171464
x_right 381.075766849
x_mid 273.850171464
 27%|█████████████████████▊                                                          | 132/485 [01:55<04:57,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 149.842441756
x_right 395.142893695
x_mid 271.842441756
 27%|█████████████████████▉                                                          | 133/485 [01:56<05:13,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 198.968260883
x_right 406.486700701
x_mid 301.968260883
 28%|██████████████████████                                                          | 134/485 [01:57<05:05,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 220.096435482
x_right 411.716706523
x_mid 315.096435482
 28%|██████████████████████▎                                                         | 135/485 [01:57<05:00,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 252.057518583
x_right 404.929249589
x_mid 328.057518583
 28%|██████████████████████▍                                                         | 136/485 [01:58<05:00,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 10.9011926294
x_right 389.295240262
x_mid 199.901192629
 28%|██████████████████████▌                                                         | 137/485 [01:59<04:56,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 44.60360881
x_right 384.889650729
x_mid 214.60360881
 28%|██████████████████████▊                                                         | 138/485 [02:00<04:54,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 85.1257158148
x_right 384.002319754
x_mid 234.125715815
 29%|██████████████████████▉                                                         | 139/485 [02:01<05:06,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 107.506593718
x_right 586.63247552
x_mid 346.506593718
 29%|███████████████████████                                                         | 140/485 [02:02<04:59,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 135.976370269
x_right 435.984578442
x_mid 285.976370269
 29%|███████████████████████▎                                                        | 141/485 [02:03<04:57,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 147.055030855
x_right 495.459268481
x_mid 321.055030855
 29%|███████████████████████▍                                                        | 142/485 [02:03<04:55,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 161.478619867
x_right 499.708895569
x_mid 330.478619867
 29%|███████████████████████▌                                                        | 143/485 [02:04<04:51,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 137.354968656
x_right 552.076784523
x_mid 344.354968656
 30%|███████████████████████▊                                                        | 144/485 [02:05<04:49,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 144.490814679
x_right 572.458969383
x_mid 357.490814679
 30%|███████████████████████▉                                                        | 145/485 [02:06<04:51,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 105.514969543
x_right 447.08903025
x_mid 275.514969543
 30%|████████████████████████                                                        | 146/485 [02:07<05:02,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 105.481804734
x_right 384.258252867
x_mid 244.481804734
 30%|████████████████████████▏                                                       | 147/485 [02:08<04:56,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 103.320481121
x_right 384.044400446
x_mid 243.320481121
 31%|████████████████████████▍                                                       | 148/485 [02:09<04:51,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 93.8279493703
x_right 382.133345756
x_mid 237.82794937
 31%|████████████████████████▌                                                       | 149/485 [02:10<04:47,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 108.786264982
x_right 380.073799199
x_mid 243.786264982
 31%|████████████████████████▋                                                       | 150/485 [02:10<04:44,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 123.221304893
x_right 379.76923954
x_mid 251.221304893
 31%|████████████████████████▉                                                       | 151/485 [02:11<04:40,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 115.397295956
x_right 375.518047358
x_mid 245.397295956
 31%|█████████████████████████                                                       | 152/485 [02:12<04:58,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 123.009758976
x_right 514.932726695
x_mid 318.009758976
 32%|█████████████████████████▏                                                      | 153/485 [02:13<04:50,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 122.175675491
x_right 374.664530537
x_mid 248.175675491
 32%|█████████████████████████▍                                                      | 154/485 [02:14<04:46,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 121.769302287
x_right 581.463782357
x_mid 350.769302287
 32%|█████████████████████████▌                                                      | 155/485 [02:15<04:41,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 133.771626681
x_right 548.255867338
x_mid 340.771626681
 32%|█████████████████████████▋                                                      | 156/485 [02:16<04:38,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 128.808911667
x_right 559.400122654
x_mid 343.808911667
 32%|█████████████████████████▉                                                      | 157/485 [02:16<04:36,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 131.196722058
x_right 568.104359705
x_mid 349.196722058
 33%|██████████████████████████                                                      | 158/485 [02:18<05:10,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 132.290666213
x_right 370.790672781
x_mid 251.290666213
 33%|██████████████████████████▏                                                     | 159/485 [02:19<05:10,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 126.893614342
x_right 370.494415742
x_mid 247.893614342
 33%|██████████████████████████▍                                                     | 160/485 [02:19<05:02,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 132.269440352
x_right 573.404537322
x_mid 352.269440352
 33%|██████████████████████████▌                                                     | 161/485 [02:20<05:05,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 138.222309765
x_right 581.343133027
x_mid 359.222309765
 33%|██████████████████████████▋                                                     | 162/485 [02:21<04:56,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 145.49205926
x_right 578.270920115
x_mid 361.49205926
 34%|██████████████████████████▉                                                     | 163/485 [02:22<04:50,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 146.903296273
x_right 565.455132253
x_mid 355.903296273
 34%|███████████████████████████                                                     | 164/485 [02:23<04:53,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 144.896403534
x_right 584.485201119
x_mid 363.896403534
 34%|███████████████████████████▏                                                    | 165/485 [02:24<04:52,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 141.628287879
x_right 566.274073888
x_mid 353.628287879
 34%|███████████████████████████▍                                                    | 166/485 [02:25<04:44,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 133.139574139
x_right 572.900806431
x_mid 352.139574139
 34%|███████████████████████████▌                                                    | 167/485 [02:26<04:41,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 139.216658252
x_right 554.715380774
x_mid 346.216658252
 35%|███████████████████████████▋                                                    | 168/485 [02:27<04:37,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 139.258218538
x_right 572.911359921
x_mid 355.258218538
 35%|███████████████████████████▉                                                    | 169/485 [02:27<04:32,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 144.403104024
x_right 581.768631042
x_mid 362.403104024
 35%|████████████████████████████                                                    | 170/485 [02:28<04:29,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 138.239485972
x_right 579.112890761
x_mid 358.239485972
 35%|████████████████████████████▏                                                   | 171/485 [02:29<04:45,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 138.124433895
x_right 580.867087576
x_mid 359.124433895
 35%|████████████████████████████▎                                                   | 172/485 [02:30<04:36,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 149.516981238
x_right 586.193661071
x_mid 367.516981238
 36%|████████████████████████████▌                                                   | 173/485 [02:31<04:31,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 141.387446387
x_right 583.752804552
x_mid 362.387446387
 36%|████████████████████████████▋                                                   | 174/485 [02:32<04:28,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 138.978615822
x_right 583.891965711
x_mid 360.978615822
 36%|████████████████████████████▊                                                   | 175/485 [02:33<04:26,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 131.079941035
x_right 543.824703339
x_mid 337.079941035
 36%|█████████████████████████████                                                   | 176/485 [02:33<04:25,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 131.639999213
x_right 549.237009506
x_mid 339.639999213
 36%|█████████████████████████████▏                                                  | 177/485 [02:34<04:40,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 133.273662487
x_right 584.481129067
x_mid 358.273662487
 37%|█████████████████████████████▎                                                  | 178/485 [02:35<04:32,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 128.903935942
x_right 578.230629601
x_mid 352.903935942
 37%|█████████████████████████████▌                                                  | 179/485 [02:36<04:27,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 128.641282418
x_right 575.979865017
x_mid 351.641282418
 37%|█████████████████████████████▋                                                  | 180/485 [02:37<04:22,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 128.107622285
x_right 579.947741872
x_mid 353.107622285
 37%|█████████████████████████████▊                                                  | 181/485 [02:38<04:20,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 125.5469655
x_right 580.300688276
x_mid 352.5469655
 38%|██████████████████████████████                                                  | 182/485 [02:39<04:19,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 131.687006547
x_right 579.099449707
x_mid 354.687006547
 38%|██████████████████████████████▏                                                 | 183/485 [02:40<04:30,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 129.352615653
x_right 580.742680256
x_mid 354.352615653
 38%|██████████████████████████████▎                                                 | 184/485 [02:41<04:28,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 133.662862464
x_right 580.886637479
x_mid 356.662862464
 38%|██████████████████████████████▌                                                 | 185/485 [02:41<04:23,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 142.558695474
x_right 582.169516408
x_mid 361.558695474
 38%|██████████████████████████████▋                                                 | 186/485 [02:42<04:18,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 145.32551882
x_right 590.76401362
x_mid 367.32551882
 39%|██████████████████████████████▊                                                 | 187/485 [02:43<04:14,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 134.22940919
x_right 584.856699751
x_mid 359.22940919
 39%|███████████████████████████████                                                 | 188/485 [02:44<04:12,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 143.264326948
x_right 578.758309365
x_mid 360.264326948
 39%|███████████████████████████████▏                                                | 189/485 [02:45<04:19,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 132.327822183
x_right 580.512408637
x_mid 356.327822183
 39%|███████████████████████████████▎                                                | 190/485 [02:46<04:25,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 131.675518787
x_right 571.578515185
x_mid 350.675518787
 39%|███████████████████████████████▌                                                | 191/485 [02:47<04:23,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 135.146554062
x_right 570.207835001
x_mid 352.146554062
 40%|███████████████████████████████▋                                                | 192/485 [02:48<04:18,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 133.682121911
x_right 578.324068868
x_mid 355.682121911
 40%|███████████████████████████████▊                                                | 193/485 [02:48<04:12,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 129.454847596
x_right 586.151771399
x_mid 357.454847596
 40%|████████████████████████████████                                                | 194/485 [02:49<04:07,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 117.137002883
x_right 585.02661003
x_mid 350.137002883
 40%|████████████████████████████████▏                                               | 195/485 [02:50<04:04,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 123.22146796
x_right 584.909814441
x_mid 353.22146796
 40%|████████████████████████████████▎                                               | 196/485 [02:51<04:24,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 154.273832438
x_right 586.31780547
x_mid 370.273832438
 41%|████████████████████████████████▍                                               | 197/485 [02:52<04:18,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 154.438811246
x_right 587.93656637
x_mid 370.438811246
 41%|████████████████████████████████▋                                               | 198/485 [02:53<04:10,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 152.444928683
x_right 586.72975937
x_mid 369.444928683
 41%|████████████████████████████████▊                                               | 199/485 [02:54<04:05,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 133.747874387
x_right 591.231346901
x_mid 361.747874387
 41%|████████████████████████████████▉                                               | 200/485 [02:54<04:02,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 145.982697613
x_right 594.443281385
x_mid 369.982697613
 41%|█████████████████████████████████▏                                              | 201/485 [02:55<04:01,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 127.560663107
x_right 588.53043837
x_mid 357.560663107
 42%|█████████████████████████████████▎                                              | 202/485 [02:56<04:13,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 136.541689615
x_right 583.610479637
x_mid 359.541689615
 42%|█████████████████████████████████▍                                              | 203/485 [02:57<04:07,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 144.936535896
x_right 581.082549301
x_mid 362.936535896
 42%|█████████████████████████████████▋                                              | 204/485 [02:58<04:02,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 140.682719701
x_right 578.325971727
x_mid 358.682719701
 42%|█████████████████████████████████▊                                              | 205/485 [02:59<03:59,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 120.125736542
x_right 580.18610879
x_mid 350.125736542
 42%|█████████████████████████████████▉                                              | 206/485 [03:00<03:56,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 130.43708451
x_right 580.026671118
x_mid 354.43708451
 43%|██████████████████████████████████▏                                             | 207/485 [03:00<03:54,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 136.672598445
x_right 579.388740555
x_mid 357.672598445
 43%|██████████████████████████████████▎                                             | 208/485 [03:01<03:57,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 134.288620031
x_right 578.578598985
x_mid 356.288620031
 43%|██████████████████████████████████▍                                             | 209/485 [03:02<04:05,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 130.831011399
x_right 577.87059031
x_mid 353.831011399
 43%|██████████████████████████████████▋                                             | 210/485 [03:03<04:00,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 142.545447302
x_right 579.140588944
x_mid 360.545447302
 44%|██████████████████████████████████▊                                             | 211/485 [03:04<03:57,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 143.566143109
x_right 575.290122989
x_mid 358.566143109
 44%|██████████████████████████████████▉                                             | 212/485 [03:05<03:53,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 139.740777693
x_right 574.790410297
x_mid 356.740777693
 44%|███████████████████████████████████▏                                            | 213/485 [03:06<03:55,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 136.033831348
x_right 571.808191036
x_mid 353.033831348
 44%|███████████████████████████████████▎                                            | 214/485 [03:07<03:52,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 142.66800885
x_right 560.793874128
x_mid 351.66800885
 44%|███████████████████████████████████▍                                            | 215/485 [03:08<04:01,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 127.102788162
x_right 568.730971066
x_mid 347.102788162
 45%|███████████████████████████████████▋                                            | 216/485 [03:08<03:56,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 121.790077176
x_right 567.070263247
x_mid 343.790077176
 45%|███████████████████████████████████▊                                            | 217/485 [03:09<03:52,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 121.233691562
x_right 581.817745223
x_mid 351.233691562
 45%|███████████████████████████████████▉                                            | 218/485 [03:10<03:49,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 117.549052349
x_right 579.577737568
x_mid 348.549052349
 45%|████████████████████████████████████                                            | 219/485 [03:11<03:51,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 130.051234625
x_right 579.037422434
x_mid 354.051234625
 45%|████████████████████████████████████▎                                           | 220/485 [03:12<03:51,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 105.689494665
x_right 578.943755903
x_mid 341.689494665
 46%|████████████████████████████████████▍                                           | 221/485 [03:13<04:06,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 110.086380575
x_right 579.811302708
x_mid 344.086380575
 46%|████████████████████████████████████▌                                           | 222/485 [03:14<04:12,  1.04it/s]
y_btm 720
image_mid 360.0
x_left 107.685990177
x_right 577.956157189
x_mid 342.685990177
 46%|████████████████████████████████████▊                                           | 223/485 [03:15<04:09,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 110.608860247
x_right 577.905877977
x_mid 343.608860247
 46%|████████████████████████████████████▉                                           | 224/485 [03:16<04:00,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 111.286186867
x_right 579.629259856
x_mid 345.286186867
 46%|█████████████████████████████████████                                           | 225/485 [03:17<03:55,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 115.093000871
x_right 574.628848596
x_mid 344.093000871
 47%|█████████████████████████████████████▎                                          | 226/485 [03:17<03:49,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 102.85059846
x_right 573.482863178
x_mid 337.85059846
 47%|█████████████████████████████████████▍                                          | 227/485 [03:18<04:03,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 108.446981599
x_right 580.626260481
x_mid 344.446981599
 47%|█████████████████████████████████████▌                                          | 228/485 [03:19<03:54,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 123.396818324
x_right 582.602855506
x_mid 352.396818324
 47%|█████████████████████████████████████▊                                          | 229/485 [03:20<03:47,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 112.586361096
x_right 574.549818802
x_mid 342.586361096
 47%|█████████████████████████████████████▉                                          | 230/485 [03:21<03:42,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 107.097776537
x_right 582.8717528
x_mid 344.097776537
 48%|██████████████████████████████████████                                          | 231/485 [03:22<03:37,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 106.562050843
x_right 574.000843393
x_mid 339.562050843
 48%|██████████████████████████████████████▎                                         | 232/485 [03:23<03:36,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 111.045436179
x_right 573.954370773
x_mid 342.045436179
 48%|██████████████████████████████████████▍                                         | 233/485 [03:24<03:46,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 104.962152441
x_right 575.296847429
x_mid 339.962152441
 48%|██████████████████████████████████████▌                                         | 234/485 [03:24<03:39,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 119.025060858
x_right 572.860516084
x_mid 345.025060858
 48%|██████████████████████████████████████▊                                         | 235/485 [03:25<03:41,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 114.53079328
x_right 575.175567729
x_mid 344.53079328
 49%|██████████████████████████████████████▉                                         | 236/485 [03:26<03:38,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 126.332290567
x_right 577.572171242
x_mid 351.332290567
 49%|███████████████████████████████████████                                         | 237/485 [03:27<03:34,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 115.958003022
x_right 576.869557484
x_mid 345.958003022
 49%|███████████████████████████████████████▎                                        | 238/485 [03:28<03:33,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 134.457009494
x_right 570.087243944
x_mid 351.457009494
 49%|███████████████████████████████████████▍                                        | 239/485 [03:29<03:41,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 129.178563723
x_right 570.987926969
x_mid 349.178563723
 49%|███████████████████████████████████████▌                                        | 240/485 [03:30<03:36,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 117.925036183
x_right 574.750281756
x_mid 345.925036183
 50%|███████████████████████████████████████▊                                        | 241/485 [03:31<03:33,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 144.495912788
x_right 589.58745842
x_mid 366.495912788
 50%|███████████████████████████████████████▉                                        | 242/485 [03:31<03:29,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 131.622742328
x_right 586.828643472
x_mid 358.622742328
 50%|████████████████████████████████████████                                        | 243/485 [03:32<03:27,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 132.636286972
x_right 588.388061028
x_mid 359.636286972
 50%|████████████████████████████████████████▏                                       | 244/485 [03:33<03:25,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 118.970445129
x_right 579.71674209
x_mid 348.970445129
 51%|████████████████████████████████████████▍                                       | 245/485 [03:34<03:23,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 146.261027487
x_right 580.099322586
x_mid 362.261027487
 51%|████████████████████████████████████████▌                                       | 246/485 [03:35<03:34,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 148.975819961
x_right 581.325250763
x_mid 364.975819961
 51%|████████████████████████████████████████▋                                       | 247/485 [03:36<03:27,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 134.711009625
x_right 580.406272235
x_mid 356.711009625
 51%|████████████████████████████████████████▉                                       | 248/485 [03:37<03:24,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 147.868634036
x_right 581.491705497
x_mid 363.868634036
 51%|█████████████████████████████████████████                                       | 249/485 [03:37<03:22,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 142.342396395
x_right 580.465547662
x_mid 361.342396395
 52%|█████████████████████████████████████████▏                                      | 250/485 [03:38<03:19,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 147.382736295
x_right 580.060176277
x_mid 363.382736295
 52%|█████████████████████████████████████████▍                                      | 251/485 [03:39<03:18,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 143.318921924
x_right 580.115581507
x_mid 361.318921924
 52%|█████████████████████████████████████████▌                                      | 252/485 [03:40<03:32,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 150.396959084
x_right 580.583678951
x_mid 365.396959084
 52%|█████████████████████████████████████████▋                                      | 253/485 [03:41<03:47,  1.02it/s]
y_btm 720
image_mid 360.0
x_left 157.645636707
x_right 579.702405061
x_mid 368.645636707
 52%|█████████████████████████████████████████▉                                      | 254/485 [03:42<03:44,  1.03it/s]
y_btm 720
image_mid 360.0
x_left 138.128981488
x_right 584.71148883
x_mid 361.128981488
 53%|██████████████████████████████████████████                                      | 255/485 [03:43<03:51,  1.01s/it]
y_btm 720
image_mid 360.0
x_left 138.124723548
x_right 596.893068355
x_mid 367.124723548
 53%|██████████████████████████████████████████▏                                     | 256/485 [03:44<03:39,  1.04it/s]
y_btm 720
image_mid 360.0
x_left 150.215066058
x_right 591.486314838
x_mid 370.215066058
 53%|██████████████████████████████████████████▍                                     | 257/485 [03:46<04:14,  1.11s/it]
y_btm 720
image_mid 360.0
x_left 132.81610859
x_right 590.792337202
x_mid 360.81610859
 53%|██████████████████████████████████████████▌                                     | 258/485 [03:47<04:05,  1.08s/it]
y_btm 720
image_mid 360.0
x_left 143.513420884
x_right 578.099716073
x_mid 360.513420884
 53%|██████████████████████████████████████████▋                                     | 259/485 [03:48<03:55,  1.04s/it]
y_btm 720
image_mid 360.0
x_left 136.956257047
x_right 490.868221462
x_mid 312.956257047
 54%|██████████████████████████████████████████▉                                     | 260/485 [03:49<04:19,  1.15s/it]
y_btm 720
image_mid 360.0
x_left 132.638917561
x_right 585.093424967
x_mid 358.638917561
 54%|███████████████████████████████████████████                                     | 261/485 [03:51<04:42,  1.26s/it]
y_btm 720
image_mid 360.0
x_left 134.648246828
x_right 582.064996896
x_mid 357.648246828
 54%|███████████████████████████████████████████▏                                    | 262/485 [03:52<04:58,  1.34s/it]
y_btm 720
image_mid 360.0
x_left 134.331219094
x_right 584.593858528
x_mid 359.331219094
 54%|███████████████████████████████████████████▍                                    | 263/485 [03:53<04:38,  1.26s/it]
y_btm 720
image_mid 360.0
x_left 127.609388565
x_right 545.539716264
x_mid 335.609388565
 54%|███████████████████████████████████████████▌                                    | 264/485 [03:54<04:14,  1.15s/it]
y_btm 720
image_mid 360.0
x_left 124.450326336
x_right 554.422625545
x_mid 338.450326336
 55%|███████████████████████████████████████████▋                                    | 265/485 [03:55<04:00,  1.09s/it]
y_btm 720
image_mid 360.0
x_left 125.337247051
x_right 558.182874508
x_mid 341.337247051
 55%|███████████████████████████████████████████▉                                    | 266/485 [03:56<04:06,  1.13s/it]
y_btm 720
image_mid 360.0
x_left 135.044100253
x_right 572.049146002
x_mid 353.044100253
 55%|████████████████████████████████████████████                                    | 267/485 [03:58<05:09,  1.42s/it]
y_btm 720
image_mid 360.0
x_left 128.995519898
x_right 582.54847078
x_mid 354.995519898
 55%|████████████████████████████████████████████▏                                   | 268/485 [04:00<05:09,  1.43s/it]
y_btm 720
image_mid 360.0
x_left 125.435646781
x_right 583.094188792
x_mid 353.435646781
 55%|████████████████████████████████████████████▎                                   | 269/485 [04:01<04:53,  1.36s/it]
y_btm 720
image_mid 360.0
x_left 121.756042189
x_right 578.61802533
x_mid 349.756042189
 56%|████████████████████████████████████████████▌                                   | 270/485 [04:02<04:58,  1.39s/it]
y_btm 720
image_mid 360.0
x_left 116.299808511
x_right 557.382387863
x_mid 336.299808511
 56%|████████████████████████████████████████████▋                                   | 271/485 [04:03<04:31,  1.27s/it]
y_btm 720
image_mid 360.0
x_left 126.863642723
x_right 576.914914019
x_mid 351.863642723
 56%|████████████████████████████████████████████▊                                   | 272/485 [04:05<04:48,  1.36s/it]
y_btm 720
image_mid 360.0
x_left 120.632485132
x_right 604.895670873
x_mid 362.632485132
 56%|█████████████████████████████████████████████                                   | 273/485 [04:06<04:20,  1.23s/it]
y_btm 720
image_mid 360.0
x_left 122.4170313
x_right 582.575263715
x_mid 352.4170313
 56%|█████████████████████████████████████████████▏                                  | 274/485 [04:07<03:57,  1.13s/it]
y_btm 720
image_mid 360.0
x_left 133.367792569
x_right 588.277125849
x_mid 360.367792569
 57%|█████████████████████████████████████████████▎                                  | 275/485 [04:08<03:39,  1.05s/it]
y_btm 720
image_mid 360.0
x_left 135.783746789
x_right 561.57916881
x_mid 347.783746789
 57%|█████████████████████████████████████████████▌                                  | 276/485 [04:09<03:27,  1.01it/s]
y_btm 720
image_mid 360.0
x_left 124.33812464
x_right 579.147445986
x_mid 351.33812464
 57%|█████████████████████████████████████████████▋                                  | 277/485 [04:10<03:35,  1.03s/it]
y_btm 720
image_mid 360.0
x_left 129.80727382
x_right 586.719335119
x_mid 357.80727382
 57%|█████████████████████████████████████████████▊                                  | 278/485 [04:11<03:21,  1.03it/s]
y_btm 720
image_mid 360.0
x_left 140.790830729
x_right 577.818873795
x_mid 358.790830729
 58%|██████████████████████████████████████████████                                  | 279/485 [04:11<03:11,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 130.984105531
x_right 576.141081866
x_mid 352.984105531
 58%|██████████████████████████████████████████████▏                                 | 280/485 [04:12<03:03,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 131.518006481
x_right 576.566554228
x_mid 353.518006481
 58%|██████████████████████████████████████████████▎                                 | 281/485 [04:13<02:58,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 133.748501587
x_right 579.890957164
x_mid 356.748501587
 58%|██████████████████████████████████████████████▌                                 | 282/485 [04:14<02:53,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 131.016185836
x_right 582.483043161
x_mid 356.016185836
 58%|██████████████████████████████████████████████▋                                 | 283/485 [04:15<02:58,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 127.482007385
x_right 571.953076851
x_mid 349.482007385
 59%|██████████████████████████████████████████████▊                                 | 284/485 [04:16<02:55,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 127.431723508
x_right 557.706519111
x_mid 342.431723508
 59%|███████████████████████████████████████████████                                 | 285/485 [04:16<02:50,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 131.77166432
x_right 542.461500135
x_mid 336.77166432
 59%|███████████████████████████████████████████████▏                                | 286/485 [04:17<02:55,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 127.527548252
x_right 566.120879193
x_mid 346.527548252
 59%|███████████████████████████████████████████████▎                                | 287/485 [04:18<02:55,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 123.579735101
x_right 514.362764913
x_mid 318.579735101
 59%|███████████████████████████████████████████████▌                                | 288/485 [04:19<02:55,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 138.320262484
x_right 529.946402244
x_mid 333.320262484
 60%|███████████████████████████████████████████████▋                                | 289/485 [04:20<03:06,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 135.025281723
x_right 575.831659538
x_mid 355.025281723
 60%|███████████████████████████████████████████████▊                                | 290/485 [04:21<03:00,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 124.551008842
x_right 577.881207728
x_mid 350.551008842
 60%|████████████████████████████████████████████████                                | 291/485 [04:22<02:53,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 136.560401475
x_right 568.971297406
x_mid 352.560401475
 60%|████████████████████████████████████████████████▏                               | 292/485 [04:23<02:49,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 121.726657226
x_right 541.79923001
x_mid 331.726657226
 60%|████████████████████████████████████████████████▎                               | 293/485 [04:24<02:46,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 125.129286927
x_right 546.719660124
x_mid 335.129286927
 61%|████████████████████████████████████████████████▍                               | 294/485 [04:24<02:41,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 132.099197051
x_right 543.906402214
x_mid 337.099197051
 61%|████████████████████████████████████████████████▋                               | 295/485 [04:25<02:47,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 127.597832181
x_right 585.478627182
x_mid 355.597832181
 61%|████████████████████████████████████████████████▊                               | 296/485 [04:26<02:47,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 126.833466557
x_right 579.656681328
x_mid 352.833466557
 61%|████████████████████████████████████████████████▉                               | 297/485 [04:27<02:43,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 141.973794038
x_right 558.981371365
x_mid 349.973794038
 61%|█████████████████████████████████████████████████▏                              | 298/485 [04:28<02:39,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 146.58242001
x_right 520.110954425
x_mid 332.58242001
 62%|█████████████████████████████████████████████████▎                              | 299/485 [04:29<02:36,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 139.838673237
x_right 560.885815287
x_mid 349.838673237
 62%|█████████████████████████████████████████████████▍                              | 300/485 [04:30<02:33,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 142.721245384
x_right 555.182139559
x_mid 348.721245384
 62%|█████████████████████████████████████████████████▋                              | 301/485 [04:30<02:32,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 144.114334157
x_right 554.866687479
x_mid 349.114334157
 62%|█████████████████████████████████████████████████▊                              | 302/485 [04:31<02:39,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 135.272385251
x_right 565.984281585
x_mid 350.272385251
 62%|█████████████████████████████████████████████████▉                              | 303/485 [04:32<02:38,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 105.248110188
x_right 560.698188519
x_mid 332.248110188
 63%|██████████████████████████████████████████████████▏                             | 304/485 [04:33<02:34,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 112.230990767
x_right 566.820286815
x_mid 339.230990767
 63%|██████████████████████████████████████████████████▎                             | 305/485 [04:34<02:31,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 119.917494091
x_right 557.862163918
x_mid 337.917494091
 63%|██████████████████████████████████████████████████▍                             | 306/485 [04:35<02:30,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 123.188326017
x_right 570.152894253
x_mid 346.188326017
 63%|██████████████████████████████████████████████████▋                             | 307/485 [04:36<02:29,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 129.613170486
x_right 558.701925473
x_mid 343.613170486
 64%|██████████████████████████████████████████████████▊                             | 308/485 [04:36<02:34,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 129.054925306
x_right 566.92323185
x_mid 347.054925306
 64%|██████████████████████████████████████████████████▉                             | 309/485 [04:37<02:32,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 130.271616097
x_right 576.33990447
x_mid 353.271616097
 64%|███████████████████████████████████████████████████▏                            | 310/485 [04:38<02:28,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 124.221000245
x_right 553.543206907
x_mid 338.221000245
 64%|███████████████████████████████████████████████████▎                            | 311/485 [04:39<02:26,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 119.607419823
x_right 584.406563364
x_mid 351.607419823
 64%|███████████████████████████████████████████████████▍                            | 312/485 [04:40<02:24,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 121.134807102
x_right 574.723402911
x_mid 347.134807102
 65%|███████████████████████████████████████████████████▋                            | 313/485 [04:41<02:26,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 128.186407583
x_right 581.834236098
x_mid 354.186407583
 65%|███████████████████████████████████████████████████▊                            | 314/485 [04:42<02:29,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 116.313055421
x_right 575.609051776
x_mid 345.313055421
 65%|███████████████████████████████████████████████████▉                            | 315/485 [04:43<02:32,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 127.729947016
x_right 604.260827212
x_mid 365.729947016
 65%|████████████████████████████████████████████████████                            | 316/485 [04:44<02:49,  1.01s/it]
y_btm 720
image_mid 360.0
x_left 124.717441186
x_right 543.625278384
x_mid 333.717441186
 65%|████████████████████████████████████████████████████▎                           | 317/485 [04:45<02:47,  1.00it/s]
y_btm 720
image_mid 360.0
x_left 125.258337393
x_right 576.953110581
x_mid 350.258337393
 66%|████████████████████████████████████████████████████▍                           | 318/485 [04:46<02:38,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 129.986258572
x_right 576.648772233
x_mid 352.986258572
 66%|████████████████████████████████████████████████████▌                           | 319/485 [04:46<02:30,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 124.860801009
x_right 574.220832615
x_mid 348.860801009
 66%|████████████████████████████████████████████████████▊                           | 320/485 [04:47<02:32,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 130.255606345
x_right 575.742173864
x_mid 352.255606345
 66%|████████████████████████████████████████████████████▉                           | 321/485 [04:48<02:26,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 124.244013204
x_right 574.944774872
x_mid 349.244013204
 66%|█████████████████████████████████████████████████████                           | 322/485 [04:49<02:21,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 122.646223013
x_right 576.065684925
x_mid 348.646223013
 67%|█████████████████████████████████████████████████████▎                          | 323/485 [04:50<02:18,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 138.682273558
x_right 568.067009096
x_mid 352.682273558
 67%|█████████████████████████████████████████████████████▍                          | 324/485 [04:51<02:15,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 139.166142972
x_right 553.402962914
x_mid 346.166142972
 67%|█████████████████████████████████████████████████████▌                          | 325/485 [04:51<02:13,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 145.728836875
x_right 492.014507775
x_mid 318.728836875
 67%|█████████████████████████████████████████████████████▊                          | 326/485 [04:52<02:15,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 135.528841052
x_right 515.251807509
x_mid 324.528841052
 67%|█████████████████████████████████████████████████████▉                          | 327/485 [04:53<02:21,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 127.840323099
x_right 516.452042992
x_mid 321.840323099
 68%|██████████████████████████████████████████████████████                          | 328/485 [04:54<02:18,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 133.827069729
x_right 573.373589868
x_mid 352.827069729
 68%|██████████████████████████████████████████████████████▎                         | 329/485 [04:55<02:14,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 145.489159181
x_right 546.081481586
x_mid 345.489159181
 68%|██████████████████████████████████████████████████████▍                         | 330/485 [04:56<02:11,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 140.915563552
x_right 540.243636572
x_mid 339.915563552
 68%|██████████████████████████████████████████████████████▌                         | 331/485 [04:57<02:09,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 149.041608972
x_right 563.436217889
x_mid 356.041608972
 68%|██████████████████████████████████████████████████████▊                         | 332/485 [04:58<02:09,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 149.316356324
x_right 574.511132814
x_mid 361.316356324
 69%|██████████████████████████████████████████████████████▉                         | 333/485 [04:58<02:13,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 149.79705472
x_right 576.63703453
x_mid 362.79705472
 69%|███████████████████████████████████████████████████████                         | 334/485 [04:59<02:10,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 145.5586848
x_right 572.087350824
x_mid 358.5586848
 69%|███████████████████████████████████████████████████████▎                        | 335/485 [05:00<02:11,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 153.16165464
x_right 576.452805449
x_mid 364.16165464
 69%|███████████████████████████████████████████████████████▍                        | 336/485 [05:01<02:11,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 146.26156324
x_right 576.808702056
x_mid 361.26156324
 69%|███████████████████████████████████████████████████████▌                        | 337/485 [05:02<02:08,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 137.175849562
x_right 577.850864467
x_mid 357.175849562
 70%|███████████████████████████████████████████████████████▊                        | 338/485 [05:03<02:05,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 133.428990742
x_right 572.903617226
x_mid 352.428990742
 70%|███████████████████████████████████████████████████████▉                        | 339/485 [05:04<02:11,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 146.708795192
x_right 573.788100162
x_mid 359.708795192
 70%|████████████████████████████████████████████████████████                        | 340/485 [05:05<02:08,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 144.055692429
x_right 572.375475814
x_mid 358.055692429
 70%|████████████████████████████████████████████████████████▏                       | 341/485 [05:05<02:04,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 143.682167742
x_right 573.0002667
x_mid 357.682167742
 71%|████████████████████████████████████████████████████████▍                       | 342/485 [05:06<02:02,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 144.30328678
x_right 572.787492598
x_mid 358.30328678
 71%|████████████████████████████████████████████████████████▌                       | 343/485 [05:07<02:02,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 140.027073743
x_right 572.794464966
x_mid 356.027073743
 71%|████████████████████████████████████████████████████████▋                       | 344/485 [05:08<02:01,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 136.280070519
x_right 574.843989169
x_mid 355.280070519
 71%|████████████████████████████████████████████████████████▉                       | 345/485 [05:09<02:03,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 134.303241867
x_right 573.402590225
x_mid 353.303241867
 71%|█████████████████████████████████████████████████████████                       | 346/485 [05:10<02:00,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 126.036945755
x_right 572.734721344
x_mid 349.036945755
 72%|█████████████████████████████████████████████████████████▏                      | 347/485 [05:11<01:57,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 124.445358988
x_right 570.538477212
x_mid 347.445358988
 72%|█████████████████████████████████████████████████████████▍                      | 348/485 [05:11<01:56,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 122.356449512
x_right 573.62713306
x_mid 347.356449512
 72%|█████████████████████████████████████████████████████████▌                      | 349/485 [05:12<01:54,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 128.118244107
x_right 575.090480963
x_mid 351.118244107
 72%|█████████████████████████████████████████████████████████▋                      | 350/485 [05:13<01:52,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 126.903287973
x_right 574.532989086
x_mid 349.903287973
 72%|█████████████████████████████████████████████████████████▉                      | 351/485 [05:14<01:52,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 129.341924508
x_right 374.658841712
x_mid 251.341924508
 73%|██████████████████████████████████████████████████████████                      | 352/485 [05:15<01:54,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 123.105275856
x_right 374.794676333
x_mid 248.105275856
 73%|██████████████████████████████████████████████████████████▏                     | 353/485 [05:16<01:52,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 117.249075783
x_right 580.36140235
x_mid 348.249075783
 73%|██████████████████████████████████████████████████████████▍                     | 354/485 [05:17<01:50,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 121.182925395
x_right 581.695547366
x_mid 351.182925395
 73%|██████████████████████████████████████████████████████████▌                     | 355/485 [05:17<01:48,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 112.92135763
x_right 581.272556178
x_mid 346.92135763
 73%|██████████████████████████████████████████████████████████▋                     | 356/485 [05:18<01:47,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 117.795187093
x_right 578.833802346
x_mid 347.795187093
 74%|██████████████████████████████████████████████████████████▉                     | 357/485 [05:19<01:46,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 109.73373052
x_right 579.897773543
x_mid 344.73373052
 74%|███████████████████████████████████████████████████████████                     | 358/485 [05:20<01:49,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 116.869326254
x_right 578.877437862
x_mid 347.869326254
 74%|███████████████████████████████████████████████████████████▏                    | 359/485 [05:21<01:47,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 118.460412492
x_right 577.20924322
x_mid 347.460412492
 74%|███████████████████████████████████████████████████████████▍                    | 360/485 [05:22<01:45,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 120.469528718
x_right 577.618480208
x_mid 348.469528718
 74%|███████████████████████████████████████████████████████████▌                    | 361/485 [05:22<01:43,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 120.214716521
x_right 578.079287344
x_mid 348.214716521
 75%|███████████████████████████████████████████████████████████▋                    | 362/485 [05:23<01:41,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 112.660807492
x_right 575.729935022
x_mid 343.660807492
 75%|███████████████████████████████████████████████████████████▉                    | 363/485 [05:24<01:40,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 117.72609678
x_right 575.813276263
x_mid 346.72609678
 75%|████████████████████████████████████████████████████████████                    | 364/485 [05:25<01:42,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 130.182399224
x_right 577.634634521
x_mid 353.182399224
 75%|████████████████████████████████████████████████████████████▏                   | 365/485 [05:26<01:43,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 130.283811657
x_right 575.780331941
x_mid 352.283811657
 75%|████████████████████████████████████████████████████████████▎                   | 366/485 [05:27<01:40,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 132.394716791
x_right 365.294794131
x_mid 248.394716791
 76%|████████████████████████████████████████████████████████████▌                   | 367/485 [05:27<01:38,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 129.610416161
x_right 578.505382588
x_mid 353.610416161
 76%|████████████████████████████████████████████████████████████▋                   | 368/485 [05:28<01:37,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 134.130749887
x_right 576.026672077
x_mid 354.130749887
 76%|████████████████████████████████████████████████████████████▊                   | 369/485 [05:29<01:35,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 137.275301014
x_right 577.884525171
x_mid 357.275301014
 76%|█████████████████████████████████████████████████████████████                   | 370/485 [05:30<01:36,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 142.248606168
x_right 576.32429328
x_mid 359.248606168
 76%|█████████████████████████████████████████████████████████████▏                  | 371/485 [05:31<01:37,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 134.438130518
x_right 576.226740393
x_mid 354.438130518
 77%|█████████████████████████████████████████████████████████████▎                  | 372/485 [05:32<01:35,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 132.248121172
x_right 576.524218123
x_mid 354.248121172
 77%|█████████████████████████████████████████████████████████████▌                  | 373/485 [05:32<01:34,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 133.70546043
x_right 574.119180089
x_mid 353.70546043
 77%|█████████████████████████████████████████████████████████████▋                  | 374/485 [05:33<01:32,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 133.810489954
x_right 573.717511853
x_mid 352.810489954
 77%|█████████████████████████████████████████████████████████████▊                  | 375/485 [05:34<01:31,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 125.516159759
x_right 570.677462419
x_mid 347.516159759
 78%|██████████████████████████████████████████████████████████████                  | 376/485 [05:35<01:30,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 122.096756195
x_right 571.443824078
x_mid 346.096756195
 78%|██████████████████████████████████████████████████████████████▏                 | 377/485 [05:36<01:32,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 130.481634553
x_right 570.345996535
x_mid 349.481634553
 78%|██████████████████████████████████████████████████████████████▎                 | 378/485 [05:37<01:30,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 128.647606424
x_right 571.935636539
x_mid 349.647606424
 78%|██████████████████████████████████████████████████████████████▌                 | 379/485 [05:38<01:29,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 123.472783106
x_right 355.623436185
x_mid 239.472783106
 78%|██████████████████████████████████████████████████████████████▋                 | 380/485 [05:38<01:27,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 126.564427079
x_right 354.370947746
x_mid 239.564427079
 79%|██████████████████████████████████████████████████████████████▊                 | 381/485 [05:39<01:26,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 116.287690476
x_right 352.034463693
x_mid 233.287690476
 79%|███████████████████████████████████████████████████████████████                 | 382/485 [05:40<01:25,  1.21it/s]
y_btm 720
image_mid 360.0
x_left 108.763155973
x_right 351.772388567
x_mid 229.763155973
 79%|███████████████████████████████████████████████████████████████▏                | 383/485 [05:41<01:26,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 115.575329564
x_right 351.083426572
x_mid 232.575329564
 79%|███████████████████████████████████████████████████████████████▎                | 384/485 [05:42<01:28,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 115.60847649
x_right 569.595805961
x_mid 341.60847649
 79%|███████████████████████████████████████████████████████████████▌                | 385/485 [05:43<01:27,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 108.456201547
x_right 564.727765815
x_mid 336.456201547
 80%|███████████████████████████████████████████████████████████████▋                | 386/485 [05:44<01:26,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 109.097047192
x_right 563.162500022
x_mid 336.097047192
 80%|███████████████████████████████████████████████████████████████▊                | 387/485 [05:44<01:26,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 116.232008105
x_right 561.158223894
x_mid 338.232008105
 80%|████████████████████████████████████████████████████████████████                | 388/485 [05:45<01:24,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 109.843109363
x_right 560.582316606
x_mid 334.843109363
 80%|████████████████████████████████████████████████████████████████▏               | 389/485 [05:46<01:22,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 343.325290293
x_right 562.084285601
x_mid 452.325290293
 80%|████████████████████████████████████████████████████████████████▎               | 390/485 [05:47<01:24,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 343.02206386
x_right 561.336986734
x_mid 452.02206386
 81%|████████████████████████████████████████████████████████████████▍               | 391/485 [05:48<01:22,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 341.396179144
x_right 341.396179144
x_mid 341.396179144
 81%|████████████████████████████████████████████████████████████████▋               | 392/485 [05:49<01:21,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 340.288609583
x_right 340.288609583
x_mid 340.288609583
 81%|████████████████████████████████████████████████████████████████▊               | 393/485 [05:50<01:25,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 339.2675474
x_right 339.2675474
x_mid 339.2675474
 81%|████████████████████████████████████████████████████████████████▉               | 394/485 [05:51<01:23,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 338.113477733
x_right 554.118337403
x_mid 446.113477733
 81%|█████████████████████████████████████████████████████████████████▏              | 395/485 [05:52<01:27,  1.03it/s]
y_btm 720
image_mid 360.0
x_left 337.27710621
x_right 553.737803033
x_mid 445.27710621
 82%|█████████████████████████████████████████████████████████████████▎              | 396/485 [05:53<01:27,  1.02it/s]
y_btm 720
image_mid 360.0
x_left 335.199698576
x_right 556.96902732
x_mid 445.199698576
 82%|█████████████████████████████████████████████████████████████████▍              | 397/485 [05:54<01:30,  1.03s/it]
y_btm 720
image_mid 360.0
x_left 334.7748857
x_right 556.901888123
x_mid 445.7748857
 82%|█████████████████████████████████████████████████████████████████▋              | 398/485 [05:55<01:36,  1.11s/it]
y_btm 720
image_mid 360.0
x_left 334.754027668
x_right 557.013979494
x_mid 445.754027668
 82%|█████████████████████████████████████████████████████████████████▊              | 399/485 [05:56<01:28,  1.03s/it]
y_btm 720
image_mid 360.0
x_left 334.255554078
x_right 556.98106758
x_mid 445.255554078
 82%|█████████████████████████████████████████████████████████████████▉              | 400/485 [05:57<01:23,  1.01it/s]
y_btm 720
image_mid 360.0
x_left 332.17775608
x_right 559.838341577
x_mid 445.17775608
 83%|██████████████████████████████████████████████████████████████████▏             | 401/485 [05:58<01:25,  1.02s/it]
y_btm 720
image_mid 360.0
x_left 330.905436552
x_right 561.306986882
x_mid 445.905436552
 83%|██████████████████████████████████████████████████████████████████▎             | 402/485 [05:59<01:21,  1.02it/s]
y_btm 720
image_mid 360.0
x_left 112.367569191
x_right 562.283192547
x_mid 336.367569191
 83%|██████████████████████████████████████████████████████████████████▍             | 403/485 [06:00<01:18,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 118.717487717
x_right 563.447185873
x_mid 340.717487717
 83%|██████████████████████████████████████████████████████████████████▋             | 404/485 [06:01<01:21,  1.00s/it]
y_btm 720
image_mid 360.0
x_left 332.030563037
x_right 563.303060639
x_mid 447.030563037
 84%|██████████████████████████████████████████████████████████████████▊             | 405/485 [06:02<01:18,  1.02it/s]
y_btm 720
image_mid 360.0
x_left 327.092756393
x_right 563.014637444
x_mid 444.092756393
 84%|██████████████████████████████████████████████████████████████████▉             | 406/485 [06:03<01:14,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 304.450140652
x_right 567.444893836
x_mid 435.450140652
 84%|███████████████████████████████████████████████████████████████████▏            | 407/485 [06:04<01:14,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 306.928318123
x_right 561.611379612
x_mid 433.928318123
 84%|███████████████████████████████████████████████████████████████████▎            | 408/485 [06:05<01:12,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 329.127805685
x_right 567.615874862
x_mid 448.127805685
 84%|███████████████████████████████████████████████████████████████████▍            | 409/485 [06:06<01:09,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 330.359239132
x_right 570.120470483
x_mid 449.359239132
 85%|███████████████████████████████████████████████████████████████████▋            | 410/485 [06:06<01:06,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 107.892855377
x_right 574.99921354
x_mid 340.892855377
 85%|███████████████████████████████████████████████████████████████████▊            | 411/485 [06:07<01:05,  1.13it/s]
y_btm 720
image_mid 360.0
x_left 97.1583372553
x_right 572.374315812
x_mid 334.158337255
 85%|███████████████████████████████████████████████████████████████████▉            | 412/485 [06:08<01:03,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 91.4507552618
x_right 573.565252225
x_mid 332.450755262
 85%|████████████████████████████████████████████████████████████████████            | 413/485 [06:09<01:03,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 323.552512778
x_right 573.48433272
x_mid 447.552512778
 85%|████████████████████████████████████████████████████████████████████▎           | 414/485 [06:10<01:01,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 92.8782042498
x_right 574.043371665
x_mid 332.87820425
 86%|████████████████████████████████████████████████████████████████████▍           | 415/485 [06:11<00:59,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 323.5838196
x_right 574.20017406
x_mid 448.5838196
 86%|████████████████████████████████████████████████████████████████████▌           | 416/485 [06:12<00:58,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 324.719936121
x_right 574.953935479
x_mid 449.719936121
 86%|████████████████████████████████████████████████████████████████████▊           | 417/485 [06:12<00:57,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 319.493214285
x_right 575.415698925
x_mid 446.493214285
 86%|████████████████████████████████████████████████████████████████████▉           | 418/485 [06:13<00:57,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 304.229019632
x_right 576.41212645
x_mid 440.229019632
 86%|█████████████████████████████████████████████████████████████████████           | 419/485 [06:14<00:57,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 287.646890647
x_right 578.96873615
x_mid 432.646890647
 87%|█████████████████████████████████████████████████████████████████████▎          | 420/485 [06:15<00:55,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 309.425286397
x_right 578.743503416
x_mid 443.425286397
 87%|█████████████████████████████████████████████████████████████████████▍          | 421/485 [06:16<00:54,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 299.541670406
x_right 589.998447897
x_mid 444.541670406
 87%|█████████████████████████████████████████████████████████████████████▌          | 422/485 [06:17<00:53,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 296.063401813
x_right 601.656704178
x_mid 448.063401813
 87%|█████████████████████████████████████████████████████████████████████▊          | 423/485 [06:18<00:55,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 284.264589132
x_right 607.551396045
x_mid 445.264589132
 87%|█████████████████████████████████████████████████████████████████████▉          | 424/485 [06:19<00:55,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 289.666858109
x_right 606.47295306
x_mid 447.666858109
 88%|██████████████████████████████████████████████████████████████████████          | 425/485 [06:20<00:56,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 285.835846735
x_right 599.768785718
x_mid 441.835846735
 88%|██████████████████████████████████████████████████████████████████████▎         | 426/485 [06:21<00:55,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 283.004636264
x_right 598.352013423
x_mid 440.004636264
 88%|██████████████████████████████████████████████████████████████████████▍         | 427/485 [06:21<00:52,  1.10it/s]
y_btm 720
image_mid 360.0
x_left 236.756675595
x_right 594.92981305
x_mid 415.756675595
 88%|██████████████████████████████████████████████████████████████████████▌         | 428/485 [06:22<00:50,  1.12it/s]
y_btm 720
image_mid 360.0
x_left 272.411980797
x_right 596.481352096
x_mid 434.411980797
 88%|██████████████████████████████████████████████████████████████████████▊         | 429/485 [06:23<00:49,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 275.314614974
x_right 598.121288095
x_mid 436.314614974
 89%|██████████████████████████████████████████████████████████████████████▉         | 430/485 [06:24<00:47,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 252.173219679
x_right 602.524421029
x_mid 427.173219679
 89%|███████████████████████████████████████████████████████████████████████         | 431/485 [06:25<00:47,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 238.07300704
x_right 603.937292305
x_mid 420.07300704
 89%|███████████████████████████████████████████████████████████████████████▎        | 432/485 [06:26<00:46,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 228.908266332
x_right 607.250470193
x_mid 417.908266332
 89%|███████████████████████████████████████████████████████████████████████▍        | 433/485 [06:26<00:44,  1.16it/s]
y_btm 720
image_mid 360.0
x_left -7.41444929103
x_right 615.496569532
x_mid 303.585550709
 89%|███████████████████████████████████████████████████████████████████████▌        | 434/485 [06:27<00:43,  1.17it/s]
y_btm 720
image_mid 360.0
x_left -14.5856688939
x_right 621.778673547
x_mid 303.414331106
 90%|███████████████████████████████████████████████████████████████████████▊        | 435/485 [06:28<00:42,  1.19it/s]
y_btm 720
image_mid 360.0
x_left -14.7294876533
x_right 657.947339511
x_mid 321.270512347
 90%|███████████████████████████████████████████████████████████████████████▉        | 436/485 [06:29<00:41,  1.18it/s]
y_btm 720
image_mid 360.0
x_left -16.5284141808
x_right 664.139044303
x_mid 323.471585819
 90%|████████████████████████████████████████████████████████████████████████        | 437/485 [06:30<00:40,  1.17it/s]
y_btm 720
image_mid 360.0
x_left -17.0549246852
x_right 660.550580076
x_mid 320.945075315
 90%|████████████████████████████████████████████████████████████████████████▏       | 438/485 [06:31<00:40,  1.16it/s]
y_btm 720
image_mid 360.0
x_left -20.3609895177
x_right 658.072260246
x_mid 318.639010482
 91%|████████████████████████████████████████████████████████████████████████▍       | 439/485 [06:32<00:39,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 207.647913034
x_right 636.29991816
x_mid 421.647913034
 91%|████████████████████████████████████████████████████████████████████████▌       | 440/485 [06:32<00:37,  1.19it/s]
y_btm 720
image_mid 360.0
x_left -21.8650535805
x_right 636.667015558
x_mid 307.13494642
 91%|████████████████████████████████████████████████████████████████████████▋       | 441/485 [06:33<00:36,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 191.873570679
x_right 633.768991891
x_mid 411.873570679
 91%|████████████████████████████████████████████████████████████████████████▉       | 442/485 [06:34<00:36,  1.19it/s]
y_btm 720
image_mid 360.0
x_left -29.1863689148
x_right 643.868464584
x_mid 306.813631085
 91%|█████████████████████████████████████████████████████████████████████████       | 443/485 [06:35<00:35,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 185.800192409
x_right 640.213376293
x_mid 412.800192409
 92%|█████████████████████████████████████████████████████████████████████████▏      | 444/485 [06:36<00:35,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 186.714174284
x_right 623.184542618
x_mid 404.714174284
 92%|█████████████████████████████████████████████████████████████████████████▍      | 445/485 [06:37<00:34,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 185.354762873
x_right 622.283819875
x_mid 403.354762873
 92%|█████████████████████████████████████████████████████████████████████████▌      | 446/485 [06:37<00:32,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 185.199099607
x_right 624.216442495
x_mid 404.199099607
 92%|█████████████████████████████████████████████████████████████████████████▋      | 447/485 [06:38<00:31,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 189.252827586
x_right 631.392322753
x_mid 410.252827586
 92%|█████████████████████████████████████████████████████████████████████████▉      | 448/485 [06:39<00:31,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 194.410569765
x_right 646.84166015
x_mid 420.410569765
 93%|██████████████████████████████████████████████████████████████████████████      | 449/485 [06:40<00:30,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 195.920795559
x_right 659.342671081
x_mid 426.920795559
 93%|██████████████████████████████████████████████████████████████████████████▏     | 450/485 [06:41<00:30,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 196.722553291
x_right 659.166171105
x_mid 427.722553291
 93%|██████████████████████████████████████████████████████████████████████████▍     | 451/485 [06:42<00:28,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 196.971698463
x_right 659.15345304
x_mid 427.971698463
 93%|██████████████████████████████████████████████████████████████████████████▌     | 452/485 [06:43<00:27,  1.18it/s]
y_btm 720
image_mid 360.0
x_left 192.929186557
x_right 656.749740133
x_mid 423.929186557
 93%|██████████████████████████████████████████████████████████████████████████▋     | 453/485 [06:43<00:26,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 192.661596156
x_right 662.98866451
x_mid 427.661596156
 94%|██████████████████████████████████████████████████████████████████████████▉     | 454/485 [06:44<00:25,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 192.550151881
x_right 659.276402158
x_mid 425.550151881
 94%|███████████████████████████████████████████████████████████████████████████     | 455/485 [06:45<00:25,  1.20it/s]
y_btm 720
image_mid 360.0
x_left 191.156161905
x_right 659.593610598
x_mid 425.156161905
 94%|███████████████████████████████████████████████████████████████████████████▏    | 456/485 [06:46<00:24,  1.19it/s]
y_btm 720
image_mid 360.0
x_left 190.36195177
x_right 656.165146102
x_mid 422.36195177
 94%|███████████████████████████████████████████████████████████████████████████▍    | 457/485 [06:47<00:24,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 190.946638325
x_right 655.078423817
x_mid 422.946638325
 94%|███████████████████████████████████████████████████████████████████████████▌    | 458/485 [06:48<00:23,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 191.447876914
x_right 656.786416547
x_mid 423.447876914
 95%|███████████████████████████████████████████████████████████████████████████▋    | 459/485 [06:49<00:22,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 190.647477243
x_right 647.757057494
x_mid 418.647477243
 95%|███████████████████████████████████████████████████████████████████████████▉    | 460/485 [06:49<00:21,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 189.720475316
x_right 648.254821819
x_mid 418.720475316
 95%|████████████████████████████████████████████████████████████████████████████    | 461/485 [06:50<00:20,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 190.270224256
x_right 655.897258974
x_mid 422.270224256
 95%|████████████████████████████████████████████████████████████████████████████▏   | 462/485 [06:51<00:19,  1.16it/s]
y_btm 720
image_mid 360.0
x_left 188.765200586
x_right 656.380534023
x_mid 421.765200586
 95%|████████████████████████████████████████████████████████████████████████████▎   | 463/485 [06:52<00:19,  1.14it/s]
y_btm 720
image_mid 360.0
x_left 188.08851754
x_right 678.082185466
x_mid 432.08851754
 96%|████████████████████████████████████████████████████████████████████████████▌   | 464/485 [06:53<00:18,  1.15it/s]
y_btm 720
image_mid 360.0
x_left 186.451460678
x_right 675.761352605
x_mid 430.451460678
 96%|████████████████████████████████████████████████████████████████████████████▋   | 465/485 [06:54<00:17,  1.17it/s]
y_btm 720
image_mid 360.0
x_left 182.241911409
x_right 679.483682905
x_mid 430.241911409
 96%|████████████████████████████████████████████████████████████████████████████▊   | 466/485 [06:55<00:17,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 184.005822488
x_right 676.856884501
x_mid 430.005822488
 96%|█████████████████████████████████████████████████████████████████████████████   | 467/485 [06:56<00:18,  1.02s/it]
y_btm 720
image_mid 360.0
x_left 184.877154052
x_right 660.464045396
x_mid 421.877154052
 96%|█████████████████████████████████████████████████████████████████████████████▏  | 468/485 [06:57<00:18,  1.08s/it]
y_btm 720
image_mid 360.0
x_left 184.022400652
x_right 662.835595001
x_mid 423.022400652
 97%|█████████████████████████████████████████████████████████████████████████████▎  | 469/485 [06:58<00:16,  1.03s/it]
y_btm 720
image_mid 360.0
x_left 183.95375853
x_right 661.259084577
x_mid 421.95375853
 97%|█████████████████████████████████████████████████████████████████████████████▌  | 470/485 [06:59<00:14,  1.01it/s]
y_btm 720
image_mid 360.0
x_left 183.308463552
x_right 658.754660787
x_mid 420.308463552
 97%|█████████████████████████████████████████████████████████████████████████████▋  | 471/485 [07:00<00:13,  1.03it/s]
y_btm 720
image_mid 360.0
x_left 186.171386602
x_right 658.113535515
x_mid 421.171386602
 97%|█████████████████████████████████████████████████████████████████████████████▊  | 472/485 [07:01<00:12,  1.04it/s]
y_btm 720
image_mid 360.0
x_left 184.797442217
x_right 652.402102678
x_mid 417.797442217
 98%|██████████████████████████████████████████████████████████████████████████████  | 473/485 [07:02<00:11,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 184.061196324
x_right 651.953286527
x_mid 417.061196324
 98%|██████████████████████████████████████████████████████████████████████████████▏ | 474/485 [07:03<00:10,  1.06it/s]
y_btm 720
image_mid 360.0
x_left 184.37052807
x_right 652.952751158
x_mid 418.37052807
 98%|██████████████████████████████████████████████████████████████████████████████▎ | 475/485 [07:04<00:09,  1.08it/s]
y_btm 720
image_mid 360.0
x_left 180.076120017
x_right 655.277094975
x_mid 417.076120017
 98%|██████████████████████████████████████████████████████████████████████████████▌ | 476/485 [07:05<00:08,  1.09it/s]
y_btm 720
image_mid 360.0
x_left 183.941464678
x_right 665.008346891
x_mid 423.941464678
 98%|██████████████████████████████████████████████████████████████████████████████▋ | 477/485 [07:05<00:07,  1.11it/s]
y_btm 720
image_mid 360.0
x_left 180.04468803
x_right 684.025115327
x_mid 431.04468803
 99%|██████████████████████████████████████████████████████████████████████████████▊ | 478/485 [07:06<00:06,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 184.134876346
x_right 682.116748602
x_mid 432.134876346
 99%|███████████████████████████████████████████████████████████████████████████████ | 479/485 [07:07<00:05,  1.11it/s]
y_btm 720
image_mid 360.0
x_left -71.31153085
x_right 681.018299677
x_mid 304.68846915
 99%|███████████████████████████████████████████████████████████████████████████████▏| 480/485 [07:08<00:04,  1.05it/s]
y_btm 720
image_mid 360.0
x_left 174.767248541
x_right 661.557100015
x_mid 417.767248541
 99%|███████████████████████████████████████████████████████████████████████████████▎| 481/485 [07:09<00:03,  1.07it/s]
y_btm 720
image_mid 360.0
x_left 178.783835864
x_right 660.243094223
x_mid 418.783835864
 99%|███████████████████████████████████████████████████████████████████████████████▌| 482/485 [07:10<00:02,  1.10it/s]
y_btm 720
image_mid 360.0
x_left -92.470020981
x_right 667.080381998
x_mid 286.529979019
100%|███████████████████████████████████████████████████████████████████████████████▋| 483/485 [07:11<00:01,  1.11it/s]
y_btm 720
image_mid 360.0
x_left -62.109932419
x_right 661.230158075
x_mid 298.890067581
100%|███████████████████████████████████████████████████████████████████████████████▊| 484/485 [07:12<00:00,  1.10it/s]
y_btm 720
image_mid 360.0
x_left -62.109932419
x_right 661.230158075
x_mid 298.890067581
100%|████████████████████████████████████████████████████████████████████████████████| 485/485 [07:13<00:00,  1.10it/s]
[MoviePy] Done.
[MoviePy] >>>> Video ready: output_images/challenge_video_output.mp4 

Wall time: 7min 15s
In [66]:
HTML("""
<video width="960" height="540" controls>
  <source src="{0}">
</video>
""".format(VIDEO_OUTPUT))
Out[66]: